New upstream version 6.7.2
authorStuart Prescott <stuart@debian.org>
Sun, 6 Oct 2024 04:08:12 +0000 (15:08 +1100)
committerStuart Prescott <stuart@debian.org>
Sun, 6 Oct 2024 04:08:12 +0000 (15:08 +1100)
1013 files changed:
.flake8
LICENSES/Apache-2.0.txt [new file with mode: 0644]
README.md
README.pyside6.md
README.pyside6_addons.md
README.pyside6_essentials.md
README.pyside6_examples.md
build_scripts/__init__.py
build_scripts/build_info_collector.py
build_scripts/config.py
build_scripts/log.py
build_scripts/main.py
build_scripts/options.py
build_scripts/platforms/linux.py
build_scripts/platforms/unix.py
build_scripts/platforms/windows_desktop.py
build_scripts/qfp_tool.py [new file with mode: 0644]
build_scripts/qp5_tool.py [deleted file]
build_scripts/setup_runner.py
build_scripts/utils.py
build_scripts/wheel_files.py
coin/dependencies.yaml
coin/instructions/common_environment.yaml
coin/instructions/execute_build_instructions.yaml
coin/instructions/execute_test_instructions.yaml
coin/instructions/find_path_to_msvc_compiler.yaml
coin/module_config.yaml
coin_build_instructions.py
coin_test_instructions.py
create_wheels.py
doc/changelogs/changes-6.6.3 [new file with mode: 0644]
doc/changelogs/changes-6.7.0 [new file with mode: 0644]
doc/changelogs/changes-6.7.1 [new file with mode: 0644]
doc/changelogs/changes-6.7.2 [new file with mode: 0644]
examples/async/eratosthenes/eratosthenes_asyncio.py
examples/async/minimal/minimal_asyncio.py
examples/bluetooth/btscanner/ui_device.py
examples/bluetooth/btscanner/ui_service.py
examples/bluetooth/heartrate_game/connectionhandler.py
examples/bluetooth/heartrate_game/devicefinder.py
examples/bluetooth/heartrate_game/heartrate_global.py
examples/charts/chartthemes/ui_themewidget.py
examples/corelib/ipc/sharedmemory/ui_dialog.py
examples/demos/colorpaletteclient/ColorPalette/ColorDialogDelete.qml [new file with mode: 0644]
examples/demos/colorpaletteclient/ColorPalette/ColorDialogEditor.qml [new file with mode: 0644]
examples/demos/colorpaletteclient/ColorPalette/ColorView.qml [new file with mode: 0644]
examples/demos/colorpaletteclient/ColorPalette/Main.qml [new file with mode: 0644]
examples/demos/colorpaletteclient/ColorPalette/ServerSelection.qml [new file with mode: 0644]
examples/demos/colorpaletteclient/ColorPalette/UserMenu.qml [new file with mode: 0644]
examples/demos/colorpaletteclient/ColorPalette/qmldir [new file with mode: 0644]
examples/demos/colorpaletteclient/QtExampleStyle/Button.qml [new file with mode: 0644]
examples/demos/colorpaletteclient/QtExampleStyle/CMakeLists.txt [new file with mode: 0644]
examples/demos/colorpaletteclient/QtExampleStyle/Popup.qml [new file with mode: 0644]
examples/demos/colorpaletteclient/QtExampleStyle/TextField.qml [new file with mode: 0644]
examples/demos/colorpaletteclient/QtExampleStyle/UIStyle.qml [new file with mode: 0644]
examples/demos/colorpaletteclient/QtExampleStyle/qmldir [new file with mode: 0644]
examples/demos/colorpaletteclient/abstractresource.py [new file with mode: 0644]
examples/demos/colorpaletteclient/basiclogin.py [new file with mode: 0644]
examples/demos/colorpaletteclient/colorpaletteclient.pyproject [new file with mode: 0644]
examples/demos/colorpaletteclient/colorpaletteclient.qrc [new file with mode: 0644]
examples/demos/colorpaletteclient/doc/colorpaletteclient.rst [new file with mode: 0644]
examples/demos/colorpaletteclient/doc/colorpaletteclient.webp [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/close.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/delete.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/dots.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/edit.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/login.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/logout.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/ok.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/plus.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/qt.png [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/qt_attribution.json [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/testserver.png [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/update.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/user.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/icons/userMask.svg [new file with mode: 0644]
examples/demos/colorpaletteclient/main.py [new file with mode: 0644]
examples/demos/colorpaletteclient/paginatedresource.py [new file with mode: 0644]
examples/demos/colorpaletteclient/rc_colorpaletteclient.py [new file with mode: 0644]
examples/demos/colorpaletteclient/restservice.py [new file with mode: 0644]
examples/demos/documentviewer/jsonviewer/jsonviewer.py
examples/demos/documentviewer/pdfviewer/pdfviewer.py
examples/demos/documentviewer/txtviewer/txtviewer.py
examples/demos/documentviewer/ui_mainwindow.py
examples/designer/taskmenuextension/doc/taskmenuextension.rst
examples/graphs/2d/hellographs/HelloGraphs/Main.qml [new file with mode: 0644]
examples/graphs/2d/hellographs/HelloGraphs/qmldir [new file with mode: 0644]
examples/graphs/2d/hellographs/doc/hellographs.rst [new file with mode: 0644]
examples/graphs/2d/hellographs/doc/hellographs.webp [new file with mode: 0644]
examples/graphs/2d/hellographs/hellographs.pyproject [new file with mode: 0644]
examples/graphs/2d/hellographs/main.py [new file with mode: 0644]
examples/graphs/3d/minimalsurfacegraph/doc/minimalsurfacegraph.rst [new file with mode: 0644]
examples/graphs/3d/minimalsurfacegraph/main.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/axesinputhandler.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/bargraph.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/custominputhandler.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/layer_1.png [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/layer_2.png [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/layer_3.png [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/license.txt [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/maptexture.jpg [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/narrowarrow.mesh [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/oilrig.mesh [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/pipe.mesh [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/raindata.txt [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/refinery.mesh [new file with mode: 0644]
examples/graphs/3d/widgetgallery/data/topography.png [new file with mode: 0644]
examples/graphs/3d/widgetgallery/doc/widgetgallery.rst [new file with mode: 0644]
examples/graphs/3d/widgetgallery/doc/widgetgallery.webp [new file with mode: 0644]
examples/graphs/3d/widgetgallery/graphmodifier.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/highlightseries.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/main.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/rainfalldata.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/scatterdatamodifier.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/scattergraph.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/surfacegraph.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/surfacegraphmodifier.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/topographicseries.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/variantbardatamapping.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/variantbardataproxy.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/variantdataset.py [new file with mode: 0644]
examples/graphs/3d/widgetgallery/widgetgallery.pyproject [new file with mode: 0644]
examples/graphs/minimalsurfacegraph/doc/minimalsurfacegraph.rst [deleted file]
examples/graphs/minimalsurfacegraph/main.py [deleted file]
examples/graphs/widgetgallery/axesinputhandler.py [deleted file]
examples/graphs/widgetgallery/bargraph.py [deleted file]
examples/graphs/widgetgallery/custominputhandler.py [deleted file]
examples/graphs/widgetgallery/data/layer_1.png [deleted file]
examples/graphs/widgetgallery/data/layer_2.png [deleted file]
examples/graphs/widgetgallery/data/layer_3.png [deleted file]
examples/graphs/widgetgallery/data/license.txt [deleted file]
examples/graphs/widgetgallery/data/maptexture.jpg [deleted file]
examples/graphs/widgetgallery/data/narrowarrow.mesh [deleted file]
examples/graphs/widgetgallery/data/oilrig.mesh [deleted file]
examples/graphs/widgetgallery/data/pipe.mesh [deleted file]
examples/graphs/widgetgallery/data/raindata.txt [deleted file]
examples/graphs/widgetgallery/data/refinery.mesh [deleted file]
examples/graphs/widgetgallery/data/topography.png [deleted file]
examples/graphs/widgetgallery/doc/widgetgallery.rst [deleted file]
examples/graphs/widgetgallery/doc/widgetgallery.webp [deleted file]
examples/graphs/widgetgallery/graphmodifier.py [deleted file]
examples/graphs/widgetgallery/highlightseries.py [deleted file]
examples/graphs/widgetgallery/main.py [deleted file]
examples/graphs/widgetgallery/rainfalldata.py [deleted file]
examples/graphs/widgetgallery/scatterdatamodifier.py [deleted file]
examples/graphs/widgetgallery/scattergraph.py [deleted file]
examples/graphs/widgetgallery/surfacegraph.py [deleted file]
examples/graphs/widgetgallery/surfacegraphmodifier.py [deleted file]
examples/graphs/widgetgallery/topographicseries.py [deleted file]
examples/graphs/widgetgallery/variantbardatamapping.py [deleted file]
examples/graphs/widgetgallery/variantbardataproxy.py [deleted file]
examples/graphs/widgetgallery/variantdataset.py [deleted file]
examples/graphs/widgetgallery/widgetgallery.pyproject [deleted file]
examples/gui/rhiwindow/doc/rhiwindow.rst
examples/multimedia/audiooutput/audiooutput.py
examples/multimedia/audiosource/audiosource.py
examples/multimedia/camera/camera.py
examples/multimedia/camera/ui_camera.py
examples/multimedia/camera/ui_camera_mobile.py
examples/multimedia/camera/ui_imagesettings.py
examples/multimedia/camera/ui_videosettings.py
examples/multimedia/camera/ui_videosettings_mobile.py
examples/multimedia/player/player.py
examples/multimedia/screencapture/screencapturepreview.py
examples/pdfwidgets/pdfviewer/rc_resources.py [new file with mode: 0644]
examples/pdfwidgets/pdfviewer/resources_rc.py [deleted file]
examples/pdfwidgets/pdfviewer/ui_mainwindow.py
examples/qml/tutorials/extending-qml-advanced/properties/doc/properties.rst
examples/qml/tutorials/extending-qml/chapter5-listproperties/doc/chapter5-listproperties.rst
examples/quickcontrols/contactslist/main.py
examples/quickcontrols/filesystemexplorer/FileSystemModule/Main.qml
examples/quickcontrols/filesystemexplorer/FileSystemModule/app.qrc
examples/quickcontrols/filesystemexplorer/FileSystemModule/icons.qrc
examples/quickcontrols/filesystemexplorer/FileSystemModule/icons/app_icon.svg [new file with mode: 0644]
examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/About.qml
examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Colors.qml
examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Editor.qml [new file with mode: 0644]
examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/FileSystemView.qml
examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Icon.qml [deleted file]
examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenu.qml
examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/MyMenuBar.qml
examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/ResizeButton.qml
examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Sidebar.qml
examples/quickcontrols/filesystemexplorer/FileSystemModule/qmldir
examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.rst
examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.webp
examples/quickcontrols/filesystemexplorer/editormodels.py [new file with mode: 0644]
examples/quickcontrols/filesystemexplorer/filesystemexplorer.py [deleted file]
examples/quickcontrols/filesystemexplorer/filesystemexplorer.pyproject
examples/quickcontrols/filesystemexplorer/main.py [new file with mode: 0644]
examples/samplebinding/doc/samplebinding.rst
examples/scriptableapplication/doc/scriptableapplication.rst
examples/scriptableapplication/mainwindow.cpp
examples/scriptableapplication/mainwindow.h
examples/scriptableapplication/pythonutils.h
examples/serialbus/can/ui_canbusdeviceinfobox.py
examples/serialbus/can/ui_canbusdeviceinfodialog.py
examples/serialbus/can/ui_connectdialog.py
examples/serialbus/can/ui_mainwindow.py
examples/serialbus/can/ui_sendframebox.py
examples/serialbus/modbus/modbusclient/ui_mainwindow.py
examples/serialbus/modbus/modbusclient/ui_settingsdialog.py
examples/serialport/terminal/ui_mainwindow.py
examples/serialport/terminal/ui_settingsdialog.py
examples/speech/hello_speak/ui_mainwindow.py
examples/sql/books/ui_bookwindow.py
examples/utils/pyside_config.py
examples/webchannel/standalone/ui_dialog.py
examples/webenginewidgets/markdowneditor/ui_mainwindow.py
examples/webenginewidgets/simplebrowser/browserwindow.py
examples/webenginewidgets/simplebrowser/downloadwidget.py
examples/webenginewidgets/simplebrowser/ui_certificateerrordialog.py
examples/webenginewidgets/simplebrowser/ui_downloadmanagerwidget.py
examples/webenginewidgets/simplebrowser/ui_downloadwidget.py
examples/webenginewidgets/simplebrowser/ui_passworddialog.py
examples/webenginewidgets/simplebrowser/webview.py
examples/widgetbinding/doc/widgetbinding.md
examples/widgets/animation/easing/ui_form.py
examples/widgets/linguist/linguist.qrc
examples/widgets/mainwindows/application/application.py
examples/widgets/mainwindows/mdi/mdi.py
examples/widgets/rhi/simplerhiwidget/doc/simplerhiwidget.rst [new file with mode: 0644]
examples/widgets/rhi/simplerhiwidget/doc/simplerhiwidget.webp [new file with mode: 0644]
examples/widgets/rhi/simplerhiwidget/examplewidget.py [new file with mode: 0644]
examples/widgets/rhi/simplerhiwidget/main.py [new file with mode: 0644]
examples/widgets/rhi/simplerhiwidget/rc_simplerhiwidget.py [new file with mode: 0644]
examples/widgets/rhi/simplerhiwidget/shader_assets/color.frag.qsb [new file with mode: 0644]
examples/widgets/rhi/simplerhiwidget/shader_assets/color.vert.qsb [new file with mode: 0644]
examples/widgets/rhi/simplerhiwidget/shaders/color.frag [new file with mode: 0644]
examples/widgets/rhi/simplerhiwidget/shaders/color.vert [new file with mode: 0644]
examples/widgets/rhi/simplerhiwidget/simplerhiwidget.pyproject [new file with mode: 0644]
examples/widgets/rhi/simplerhiwidget/simplerhiwidget.qrc [new file with mode: 0644]
examples/widgets/richtext/textedit/textedit.py
requirements-doc.txt
requirements.txt
sources/pyside-tools/CMakeLists.txt
sources/pyside-tools/android_deploy.py
sources/pyside-tools/android_deploy.pyproject
sources/pyside-tools/cmake/PySideAndroid.cmake
sources/pyside-tools/deploy.py
sources/pyside-tools/deploy.pyproject
sources/pyside-tools/deploy_lib/__init__.py
sources/pyside-tools/deploy_lib/android/__init__.py
sources/pyside-tools/deploy_lib/android/android_config.py
sources/pyside-tools/deploy_lib/android/android_helper.py
sources/pyside-tools/deploy_lib/android/buildozer.py
sources/pyside-tools/deploy_lib/config.py
sources/pyside-tools/deploy_lib/default.spec
sources/pyside-tools/deploy_lib/dependency_util.py [new file with mode: 0644]
sources/pyside-tools/deploy_lib/deploy_util.py
sources/pyside-tools/deploy_lib/nuitka_helper.py
sources/pyside-tools/deploy_lib/python_helper.py
sources/pyside-tools/metaobjectdump.py
sources/pyside-tools/project.py
sources/pyside-tools/project/__init__.py
sources/pyside-tools/project/project_data.py
sources/pyside-tools/project/utils.py
sources/pyside-tools/pyside_tool.py
sources/pyside-tools/qml.py
sources/pyside6/.cmake.conf
sources/pyside6/PySide6/Qt3DAnimation/CMakeLists.txt
sources/pyside6/PySide6/Qt3DAnimation/typesystem_3danimation.xml
sources/pyside6/PySide6/Qt3DCore/CMakeLists.txt
sources/pyside6/PySide6/Qt3DCore/typesystem_3dcore.xml
sources/pyside6/PySide6/Qt3DExtras/CMakeLists.txt
sources/pyside6/PySide6/Qt3DExtras/typesystem_3dextras.xml
sources/pyside6/PySide6/Qt3DInput/typesystem_3dinput.xml
sources/pyside6/PySide6/Qt3DLogic/typesystem_3dlogic.xml
sources/pyside6/PySide6/Qt3DRender/CMakeLists.txt
sources/pyside6/PySide6/Qt3DRender/typesystem_3drender.xml
sources/pyside6/PySide6/QtAsyncio/__init__.py
sources/pyside6/PySide6/QtAsyncio/events.py
sources/pyside6/PySide6/QtAsyncio/futures.py
sources/pyside6/PySide6/QtAsyncio/tasks.py
sources/pyside6/PySide6/QtAxContainer/typesystem_axcontainer.xml
sources/pyside6/PySide6/QtBluetooth/typesystem_bluetooth.xml
sources/pyside6/PySide6/QtCharts/CMakeLists.txt
sources/pyside6/PySide6/QtCharts/typesystem_charts.xml
sources/pyside6/PySide6/QtConcurrent/CMakeLists.txt
sources/pyside6/PySide6/QtConcurrent/typesystem_concurrent.xml
sources/pyside6/PySide6/QtCore/CMakeLists.txt
sources/pyside6/PySide6/QtCore/QtCore_global.post.h.in
sources/pyside6/PySide6/QtCore/glue/core_snippets.cpp
sources/pyside6/PySide6/QtCore/glue/core_snippets_p.h
sources/pyside6/PySide6/QtCore/glue/qiopipe.cpp [new file with mode: 0644]
sources/pyside6/PySide6/QtCore/glue/qtcorehelper.cpp
sources/pyside6/PySide6/QtCore/typesystem_core.xml
sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
sources/pyside6/PySide6/QtDBus/typesystem_dbus.xml
sources/pyside6/PySide6/QtDataVisualization/CMakeLists.txt
sources/pyside6/PySide6/QtDataVisualization/typesystem_datavisualization.xml
sources/pyside6/PySide6/QtDesigner/CMakeLists.txt
sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp
sources/pyside6/PySide6/QtDesigner/typesystem_designer.xml
sources/pyside6/PySide6/QtGraphs/CMakeLists.txt
sources/pyside6/PySide6/QtGraphs/qtgraphs_helper.cpp
sources/pyside6/PySide6/QtGraphs/typesystem_graphs.xml
sources/pyside6/PySide6/QtGui/CMakeLists.txt
sources/pyside6/PySide6/QtGui/typesystem_gui.xml
sources/pyside6/PySide6/QtGui/typesystem_gui_common.xml
sources/pyside6/PySide6/QtGui/typesystem_gui_rhi.xml
sources/pyside6/PySide6/QtGui/typesystem_gui_win.xml
sources/pyside6/PySide6/QtGui/typesystem_gui_x11.xml
sources/pyside6/PySide6/QtHelp/CMakeLists.txt
sources/pyside6/PySide6/QtHelp/typesystem_help.xml
sources/pyside6/PySide6/QtHttpServer/CMakeLists.txt
sources/pyside6/PySide6/QtHttpServer/typesystem_httpserver.xml
sources/pyside6/PySide6/QtLocation/typesystem_location.xml
sources/pyside6/PySide6/QtMultimedia/CMakeLists.txt
sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml
sources/pyside6/PySide6/QtMultimediaWidgets/CMakeLists.txt
sources/pyside6/PySide6/QtMultimediaWidgets/typesystem_multimediawidgets.xml
sources/pyside6/PySide6/QtNetwork/CMakeLists.txt
sources/pyside6/PySide6/QtNetwork/typesystem_network.xml
sources/pyside6/PySide6/QtNetworkAuth/CMakeLists.txt
sources/pyside6/PySide6/QtNetworkAuth/typesystem_networkauth.xml
sources/pyside6/PySide6/QtNfc/CMakeLists.txt
sources/pyside6/PySide6/QtNfc/typesystem_nfc.xml
sources/pyside6/PySide6/QtOpenGL/CMakeLists.txt
sources/pyside6/PySide6/QtOpenGL/typesystem_opengl.xml
sources/pyside6/PySide6/QtOpenGLWidgets/CMakeLists.txt
sources/pyside6/PySide6/QtOpenGLWidgets/typesystem_openglwidgets.xml
sources/pyside6/PySide6/QtPdf/CMakeLists.txt
sources/pyside6/PySide6/QtPdf/typesystem_pdf.xml
sources/pyside6/PySide6/QtPdfWidgets/CMakeLists.txt
sources/pyside6/PySide6/QtPdfWidgets/typesystem_pdfwidgets.xml
sources/pyside6/PySide6/QtPositioning/CMakeLists.txt
sources/pyside6/PySide6/QtPositioning/typesystem_positioning.xml
sources/pyside6/PySide6/QtPrintSupport/CMakeLists.txt
sources/pyside6/PySide6/QtPrintSupport/typesystem_printsupport.xml
sources/pyside6/PySide6/QtQml/CMakeLists.txt
sources/pyside6/PySide6/QtQml/pysideqmlvolatilebool.cpp
sources/pyside6/PySide6/QtQml/typesystem_qml.xml
sources/pyside6/PySide6/QtQuick/CMakeLists.txt
sources/pyside6/PySide6/QtQuick/pysidequickregistertype.cpp
sources/pyside6/PySide6/QtQuick/typesystem_quick.xml
sources/pyside6/PySide6/QtQuick3D/CMakeLists.txt
sources/pyside6/PySide6/QtQuick3D/typesystem_quick3d.xml
sources/pyside6/PySide6/QtQuickControls2/CMakeLists.txt
sources/pyside6/PySide6/QtQuickControls2/typesystem_quickcontrols2.xml
sources/pyside6/PySide6/QtQuickTest/CMakeLists.txt [new file with mode: 0644]
sources/pyside6/PySide6/QtQuickTest/typesystem_quicktest.xml [new file with mode: 0644]
sources/pyside6/PySide6/QtQuickWidgets/CMakeLists.txt
sources/pyside6/PySide6/QtQuickWidgets/typesystem_quickwidgets.xml
sources/pyside6/PySide6/QtRemoteObjects/CMakeLists.txt
sources/pyside6/PySide6/QtRemoteObjects/typesystem_remoteobjects.xml
sources/pyside6/PySide6/QtScxml/typesystem_scxml.xml
sources/pyside6/PySide6/QtSensors/typesystem_sensors.xml
sources/pyside6/PySide6/QtSerialBus/CMakeLists.txt
sources/pyside6/PySide6/QtSerialBus/typesystem_serialbus.xml
sources/pyside6/PySide6/QtSerialPort/typesystem_serialport.xml
sources/pyside6/PySide6/QtSpatialAudio/CMakeLists.txt
sources/pyside6/PySide6/QtSpatialAudio/typesystem_spatialaudio.xml
sources/pyside6/PySide6/QtSql/CMakeLists.txt
sources/pyside6/PySide6/QtSql/typesystem_sql.xml
sources/pyside6/PySide6/QtStateMachine/CMakeLists.txt
sources/pyside6/PySide6/QtStateMachine/typesystem_statemachine.xml
sources/pyside6/PySide6/QtSvg/CMakeLists.txt
sources/pyside6/PySide6/QtSvg/typesystem_svg.xml
sources/pyside6/PySide6/QtSvgWidgets/CMakeLists.txt
sources/pyside6/PySide6/QtSvgWidgets/typesystem_svgwidgets.xml
sources/pyside6/PySide6/QtTest/CMakeLists.txt
sources/pyside6/PySide6/QtTest/typesystem_test.xml
sources/pyside6/PySide6/QtTextToSpeech/CMakeLists.txt
sources/pyside6/PySide6/QtTextToSpeech/typesystem_texttospeech.xml
sources/pyside6/PySide6/QtUiTools/CMakeLists.txt
sources/pyside6/PySide6/QtUiTools/typesystem_uitools.xml
sources/pyside6/PySide6/QtWebChannel/CMakeLists.txt
sources/pyside6/PySide6/QtWebChannel/typesystem_webchannel.xml
sources/pyside6/PySide6/QtWebEngineCore/CMakeLists.txt
sources/pyside6/PySide6/QtWebEngineCore/typesystem_webenginecore.xml
sources/pyside6/PySide6/QtWebEngineQuick/CMakeLists.txt
sources/pyside6/PySide6/QtWebEngineQuick/typesystem_webenginequick.xml
sources/pyside6/PySide6/QtWebEngineWidgets/CMakeLists.txt
sources/pyside6/PySide6/QtWebEngineWidgets/typesystem_webenginewidgets.xml
sources/pyside6/PySide6/QtWebSockets/CMakeLists.txt
sources/pyside6/PySide6/QtWebSockets/typesystem_websockets.xml
sources/pyside6/PySide6/QtWidgets/CMakeLists.txt
sources/pyside6/PySide6/QtWidgets/typesystem_widgets.xml
sources/pyside6/PySide6/QtWidgets/typesystem_widgets_common.xml
sources/pyside6/PySide6/QtXml/CMakeLists.txt
sources/pyside6/PySide6/QtXml/typesystem_xml.xml
sources/pyside6/PySide6/doc/qtqml_functions.rst [new file with mode: 0644]
sources/pyside6/PySide6/doc/qtquicktest.rst [new file with mode: 0644]
sources/pyside6/PySide6/doc/qtuitools.rst [new file with mode: 0644]
sources/pyside6/PySide6/glue/qtcore.cpp
sources/pyside6/PySide6/glue/qtgraphs.cpp
sources/pyside6/PySide6/glue/qtgui.cpp
sources/pyside6/PySide6/glue/qtmultimedia.cpp
sources/pyside6/PySide6/glue/qtnetwork.cpp
sources/pyside6/PySide6/glue/qtnetworkauth.cpp
sources/pyside6/PySide6/glue/qtpositioning.cpp [new file with mode: 0644]
sources/pyside6/PySide6/glue/qtqml.cpp
sources/pyside6/PySide6/glue/qtquicktest.cpp [new file with mode: 0644]
sources/pyside6/PySide6/glue/qtuitools.cpp
sources/pyside6/PySide6/glue/qtwebenginecore.cpp
sources/pyside6/PySide6/glue/qtwidgets.cpp
sources/pyside6/PySide6/qiopipe.h [new file with mode: 0644]
sources/pyside6/PySide6/qpydesignerextensions.h
sources/pyside6/PySide6/qpyqmlparserstatus.h
sources/pyside6/PySide6/qpyqmlpropertyvaluesource.h
sources/pyside6/PySide6/qpytextobject.h
sources/pyside6/PySide6/qtcorehelper.h
sources/pyside6/PySide6/qtdatavisualization_helper.h
sources/pyside6/PySide6/qtdbushelper.h
sources/pyside6/PySide6/qtgraphs_helper.h
sources/pyside6/PySide6/qtguihelper.h
sources/pyside6/PySide6/support/deprecated.py
sources/pyside6/PySide6/support/generate_pyi.py
sources/pyside6/cmake/Macros/PySideModules.cmake
sources/pyside6/cmake/PySideHelpers.cmake
sources/pyside6/doc/CMakeLists.txt
sources/pyside6/doc/PySide6/QtAsyncio/index.rst
sources/pyside6/doc/_static/css/qt_style.css
sources/pyside6/doc/_tags/android.rst [new file with mode: 0644]
sources/pyside6/doc/_tags/tagsindex.rst [new file with mode: 0644]
sources/pyside6/doc/commercial/index.rst
sources/pyside6/doc/conf.py.in
sources/pyside6/doc/considerations.rst
sources/pyside6/doc/contents.rst
sources/pyside6/doc/deployment/deployment-pyside6-android-deploy.rst [new file with mode: 0644]
sources/pyside6/doc/deployment/deployment-pyside6-deploy.rst
sources/pyside6/doc/deployment/index.rst
sources/pyside6/doc/developer/adapt_qt.rst
sources/pyside6/doc/developer/add_module.rst
sources/pyside6/doc/developer/add_tool.rst
sources/pyside6/doc/developer/extras.rst
sources/pyside6/doc/extras/QtCore.ClassInfo.rst
sources/pyside6/doc/extras/QtCore.Property.rst
sources/pyside6/doc/extras/QtCore.QEnum.rst
sources/pyside6/doc/extras/QtCore.QFlag.rst [new file with mode: 0644]
sources/pyside6/doc/extras/QtCore.Signal.rst
sources/pyside6/doc/extras/QtCore.Slot.rst
sources/pyside6/doc/extras/QtDesigner.QPyDesignerContainerExtension.rst
sources/pyside6/doc/extras/QtDesigner.QPyDesignerCustomWidgetCollection.rst
sources/pyside6/doc/extras/QtDesigner.QPyDesignerMemberSheetExtension.rst
sources/pyside6/doc/extras/QtDesigner.QPyDesignerTaskMenuExtension.rst
sources/pyside6/doc/extras/QtDesigner.rst
sources/pyside6/doc/extras/QtQml.ListProperty.rst [new file with mode: 0644]
sources/pyside6/doc/extras/QtQml.QPyQmlParserStatus.rst
sources/pyside6/doc/extras/QtQml.QPyQmlPropertyValueSource.rst
sources/pyside6/doc/extras/QtQml.QmlAnonymous.rst
sources/pyside6/doc/extras/QtQml.QmlAttached.rst
sources/pyside6/doc/extras/QtQml.QmlElement.rst
sources/pyside6/doc/extras/QtQml.QmlExtended.rst
sources/pyside6/doc/extras/QtQml.QmlForeign.rst
sources/pyside6/doc/extras/QtQml.QmlNamedElement.rst
sources/pyside6/doc/extras/QtQml.QmlSingleton.rst
sources/pyside6/doc/extras/QtQml.QmlUncreatable.rst
sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst [deleted file]
sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonType.rst [deleted file]
sources/pyside6/doc/extras/QtQml.qmlRegisterType.rst [deleted file]
sources/pyside6/doc/extras/QtQml.qmlRegisterUncreatableType.rst [deleted file]
sources/pyside6/doc/extras/QtQuickTest.rst [new file with mode: 0644]
sources/pyside6/doc/extras/QtUiTools.loadUiType.rst [deleted file]
sources/pyside6/doc/extras/QtUiTools.rst
sources/pyside6/doc/extras/QtWidgets.rst
sources/pyside6/doc/faq/typesoffiles.rst
sources/pyside6/doc/faq/whatisqt.rst
sources/pyside6/doc/faq/whichide.rst
sources/pyside6/doc/gettingstarted/index.rst
sources/pyside6/doc/gettingstarted/package_details.rst
sources/pyside6/doc/gettingstarted/windows.rst
sources/pyside6/doc/index.rst
sources/pyside6/doc/inheritance_diagram.py
sources/pyside6/doc/inheritance_graph.py
sources/pyside6/doc/modules.rst
sources/pyside6/doc/pysideinclude.py
sources/pyside6/doc/qdoc_spawner.py.in
sources/pyside6/doc/qtattributionsscannertorst.py
sources/pyside6/doc/qtmodules/pyside-qtquicktest.qdocconf.in [new file with mode: 0644]
sources/pyside6/doc/tools/index.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-assistant.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-designer.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-genpyi.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-linguist.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-lrelease.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-lupdate.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-metaobjectdump.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-project.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-qml.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-qmlcachegen.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-qmllint.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-qmltyperegistrar.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-rcc.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside-uic.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-assistant_screenshot.webp [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-balsam.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-balsamui.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-balsamui_screenshot.webp [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-designer_base_screenshot.webp [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-designer_customwidgets_screenshot.webp [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-designer_screenshot.webp [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-designer_sections_screenshot.webp [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-linguist_screenshot.webp [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-qmlimportscanner.rst [new file with mode: 0644]
sources/pyside6/doc/tools/pyside6-qsb.rst [new file with mode: 0644]
sources/pyside6/doc/tutorials/basictutorial/qrcfiles.rst
sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst
sources/pyside6/doc/tutorials/basictutorial/translations.rst
sources/pyside6/doc/tutorials/basictutorial/uifiles.rst
sources/pyside6/doc/tutorials/debugging/mixed_debugging.rst
sources/pyside6/doc/tutorials/debugging/qml_debugging.rst
sources/pyside6/doc/tutorials/debugging/qtcreator/qtcreator.rst
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/Main.qml
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/app.qrc
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons.qrc
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/app_icon.svg [new file with mode: 0644]
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/About.qml
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Editor.qml [new file with mode: 0644]
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/FileSystemView.qml
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Icon.qml [deleted file]
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/MyMenu.qml
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/MyMenuBar.qml
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/ResizeButton.qml
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Sidebar.qml
sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qmldir
sources/pyside6/doc/tutorials/extendedexplorer/editormodels.py [new file with mode: 0644]
sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.md
sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.py [deleted file]
sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.pyproject
sources/pyside6/doc/tutorials/extendedexplorer/main.py [new file with mode: 0644]
sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.webp
sources/pyside6/doc/tutorials/qmlapp/qmlapplication.rst
sources/pyside6/libpyside/CMakeLists.txt
sources/pyside6/libpyside/class_property.cpp
sources/pyside6/libpyside/dynamicqmetaobject.cpp
sources/pyside6/libpyside/feature_select.cpp
sources/pyside6/libpyside/globalreceiverv2.cpp
sources/pyside6/libpyside/globalreceiverv2.h
sources/pyside6/libpyside/pyside.cpp
sources/pyside6/libpyside/pysideclassdecorator.cpp
sources/pyside6/libpyside/pysideclassdecorator_p.h
sources/pyside6/libpyside/pysideclassinfo.cpp
sources/pyside6/libpyside/pysideclassinfo.h
sources/pyside6/libpyside/pysideclassinfo_p.h
sources/pyside6/libpyside/pysidemetafunction_p.h
sources/pyside6/libpyside/pysidemetatype.h
sources/pyside6/libpyside/pysideproperty.cpp
sources/pyside6/libpyside/pysideqhash.h
sources/pyside6/libpyside/pysideqobject.h
sources/pyside6/libpyside/pysidesignal.cpp
sources/pyside6/libpyside/pysidesignal.h
sources/pyside6/libpyside/pysidesignal_p.h
sources/pyside6/libpyside/pysidestaticstrings.cpp
sources/pyside6/libpyside/pysidestaticstrings.h
sources/pyside6/libpyside/pysideutils.h
sources/pyside6/libpyside/qobjectconnect.cpp
sources/pyside6/libpyside/signalmanager.cpp
sources/pyside6/libpyside/signalmanager.h
sources/pyside6/libpysideqml/pysideqmlattached.cpp
sources/pyside6/libpysideqml/pysideqmlattached.h
sources/pyside6/libpysideqml/pysideqmlextended.cpp
sources/pyside6/libpysideqml/pysideqmlforeign.cpp
sources/pyside6/libpysideqml/pysideqmllistproperty.cpp
sources/pyside6/libpysideqml/pysideqmlmetacallerror.cpp
sources/pyside6/libpysideqml/pysideqmlmetacallerror_p.h
sources/pyside6/libpysideqml/pysideqmlnamedelement.cpp
sources/pyside6/libpysideqml/pysideqmlregistertype.cpp
sources/pyside6/libpysideqml/pysideqmlregistertype.h
sources/pyside6/libpysideqml/pysideqmlregistertype_p.h
sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp
sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h
sources/pyside6/libpysideqml/pysideqmluncreatable.cpp
sources/pyside6/libpysideqml/pysideqmluncreatable.h
sources/pyside6/plugins/designer/CMakeLists.txt
sources/pyside6/plugins/designer/designercustomwidgets.cpp
sources/pyside6/plugins/uitools/customwidget.h
sources/pyside6/tests/CMakeLists.txt
sources/pyside6/tests/QtAsyncio/qasyncio_test_cancel_taskgroup.py [new file with mode: 0644]
sources/pyside6/tests/QtCore/CMakeLists.txt
sources/pyside6/tests/QtCore/blocking_signals_test.py
sources/pyside6/tests/QtCore/bug_927.py
sources/pyside6/tests/QtCore/bug_987.py
sources/pyside6/tests/QtCore/bug_PYSIDE-164.py
sources/pyside6/tests/QtCore/bug_PYSIDE-2745.py [new file with mode: 0644]
sources/pyside6/tests/QtCore/errormessages_with_features_test.py
sources/pyside6/tests/QtCore/hash_test.py
sources/pyside6/tests/QtCore/qbytearray_test.py
sources/pyside6/tests/QtCore/qiopipe_test.py [new file with mode: 0644]
sources/pyside6/tests/QtCore/qlockfile_test.py
sources/pyside6/tests/QtCore/qmetaobject_test.py
sources/pyside6/tests/QtCore/qmimedatabase_test.py
sources/pyside6/tests/QtCore/qobject_connect_notify_test.py
sources/pyside6/tests/QtCore/qobject_event_filter_test.py
sources/pyside6/tests/QtCore/qslot_object_test.py
sources/pyside6/tests/QtCore/qtimer_singleshot_test.py
sources/pyside6/tests/QtCore/thread_signals_test.py
sources/pyside6/tests/QtGui/qtransform_test.py
sources/pyside6/tests/QtGui/timed_app_and_patching_test.py
sources/pyside6/tests/QtQml/CMakeLists.txt
sources/pyside6/tests/QtQml/listproperty.py
sources/pyside6/tests/QtQml/listproperty.qml [new file with mode: 0644]
sources/pyside6/tests/QtQml/qmlregistertype_test.py [new file with mode: 0644]
sources/pyside6/tests/QtQml/qmlregistertype_test.qml [new file with mode: 0644]
sources/pyside6/tests/QtQml/registersingletontype.py
sources/pyside6/tests/QtQml/registersingletontype.qml
sources/pyside6/tests/QtQuickTest/CMakeLists.txt [new file with mode: 0644]
sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/data/tst_setup.qml [new file with mode: 0644]
sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/imports/ImportPathQmlModule/ImportPathQmlType.qml [new file with mode: 0644]
sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/imports/ImportPathQmlModule/qmldir [new file with mode: 0644]
sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/quicktestmainwithsetup.pyproject [new file with mode: 0644]
sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/tst_quicktestmainwithsetup.py [new file with mode: 0644]
sources/pyside6/tests/QtWidgets/CMakeLists.txt
sources/pyside6/tests/QtWidgets/qdialog_test.py [new file with mode: 0644]
sources/pyside6/tests/manually/lazytiming.py [new file with mode: 0644]
sources/pyside6/tests/pysidetest/CMakeLists.txt
sources/pyside6/tests/pysidetest/multiple_inheritance_test.py
sources/pyside6/tests/pysidetest/qvariant_test.py
sources/pyside6/tests/pysidetest/repr_test.py
sources/pyside6/tests/pysidetest/signalwithdefaultvalue_test.py
sources/pyside6/tests/pysidetest/testobject.cpp
sources/pyside6/tests/pysidetest/testobject.h
sources/pyside6/tests/pysidetest/testqvariantenum.h
sources/pyside6/tests/pysidetest/typedef_signal_test.py
sources/pyside6/tests/pysidetest/typesystem_pysidetest.xml
sources/pyside6/tests/registry/util.py
sources/pyside6/tests/signals/CMakeLists.txt
sources/pyside6/tests/signals/args_dont_match_test.py
sources/pyside6/tests/signals/bug_311.py
sources/pyside6/tests/signals/bug_312.py
sources/pyside6/tests/signals/bug_319.py
sources/pyside6/tests/signals/bug_79.py
sources/pyside6/tests/signals/decorators_test.py
sources/pyside6/tests/signals/invalid_callback_test.py
sources/pyside6/tests/signals/lambda_gui_test.py
sources/pyside6/tests/signals/lambda_test.py
sources/pyside6/tests/signals/leaking_signal_test.py
sources/pyside6/tests/signals/multiple_connections_gui_test.py
sources/pyside6/tests/signals/multiple_connections_test.py
sources/pyside6/tests/signals/pysignal_test.py
sources/pyside6/tests/signals/qobject_callable_connect_test.py [new file with mode: 0644]
sources/pyside6/tests/signals/qobject_destroyed_test.py
sources/pyside6/tests/signals/qobject_sender_test.py
sources/pyside6/tests/signals/ref01_test.py
sources/pyside6/tests/signals/ref02_test.py
sources/pyside6/tests/signals/ref03_test.py
sources/pyside6/tests/signals/ref04_test.py
sources/pyside6/tests/signals/ref05_test.py
sources/pyside6/tests/signals/ref06_test.py
sources/pyside6/tests/signals/segfault_proxyparent_test.py
sources/pyside6/tests/signals/self_connect_test.py
sources/pyside6/tests/signals/short_circuit_test.py
sources/pyside6/tests/signals/signal2signal_connect_test.py
sources/pyside6/tests/signals/signal_autoconnect_test.py
sources/pyside6/tests/signals/signal_connectiontype_support_test.py
sources/pyside6/tests/signals/signal_emission_gui_test.py
sources/pyside6/tests/signals/signal_emission_test.py
sources/pyside6/tests/signals/signal_manager_refcount_test.py
sources/pyside6/tests/signals/signal_signature_test.py
sources/pyside6/tests/signals/signal_with_primitive_type_test.py
sources/pyside6/tests/signals/signals.pyproject [new file with mode: 0644]
sources/pyside6/tests/signals/slot_reference_count_test.py
sources/pyside6/tests/signals/static_metaobject_test.py
sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py
sources/pyside6/tests/tools/pyside6-deploy/test_pyside6_deploy.py
sources/shiboken6/.cmake.conf
sources/shiboken6/ApiExtractor/CMakeLists.txt
sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
sources/shiboken6/ApiExtractor/abstractmetabuilder.h
sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
sources/shiboken6/ApiExtractor/abstractmetafunction.cpp
sources/shiboken6/ApiExtractor/abstractmetafunction.h
sources/shiboken6/ApiExtractor/abstractmetalang.cpp
sources/shiboken6/ApiExtractor/abstractmetalang.h
sources/shiboken6/ApiExtractor/abstractmetalang_enums.h
sources/shiboken6/ApiExtractor/abstractmetatype.cpp
sources/shiboken6/ApiExtractor/abstractmetatype.h
sources/shiboken6/ApiExtractor/addedfunction.cpp
sources/shiboken6/ApiExtractor/addedfunction.h
sources/shiboken6/ApiExtractor/addedfunction_p.h
sources/shiboken6/ApiExtractor/anystringview_helpers.cpp [new file with mode: 0644]
sources/shiboken6/ApiExtractor/anystringview_helpers.h [new file with mode: 0644]
sources/shiboken6/ApiExtractor/apiextractor.cpp
sources/shiboken6/ApiExtractor/apiextractor.h
sources/shiboken6/ApiExtractor/apiextractorflags.h
sources/shiboken6/ApiExtractor/apiextractorresult.cpp
sources/shiboken6/ApiExtractor/apiextractorresult.h
sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp
sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.h
sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp
sources/shiboken6/ApiExtractor/clangparser/clangutils.cpp
sources/shiboken6/ApiExtractor/clangparser/clangutils.h
sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp
sources/shiboken6/ApiExtractor/clangparser/compilersupport.h
sources/shiboken6/ApiExtractor/classdocumentation.cpp
sources/shiboken6/ApiExtractor/classdocumentation.h
sources/shiboken6/ApiExtractor/codesnip.cpp
sources/shiboken6/ApiExtractor/complextypeentry.h
sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp
sources/shiboken6/ApiExtractor/docparser.cpp
sources/shiboken6/ApiExtractor/docparser.h
sources/shiboken6/ApiExtractor/documentation.cpp
sources/shiboken6/ApiExtractor/documentation.h
sources/shiboken6/ApiExtractor/dotview.cpp
sources/shiboken6/ApiExtractor/doxygenparser.cpp
sources/shiboken6/ApiExtractor/enumtypeentry.h
sources/shiboken6/ApiExtractor/fileout.cpp
sources/shiboken6/ApiExtractor/functiontypeentry.h
sources/shiboken6/ApiExtractor/include.cpp
sources/shiboken6/ApiExtractor/include.h
sources/shiboken6/ApiExtractor/messages.cpp
sources/shiboken6/ApiExtractor/messages.h
sources/shiboken6/ApiExtractor/modifications.cpp
sources/shiboken6/ApiExtractor/modifications.h
sources/shiboken6/ApiExtractor/parser/codemodel.cpp
sources/shiboken6/ApiExtractor/parser/codemodel.h
sources/shiboken6/ApiExtractor/parser/codemodel_enums.h
sources/shiboken6/ApiExtractor/parser/enumvalue.cpp
sources/shiboken6/ApiExtractor/parser/enumvalue.h
sources/shiboken6/ApiExtractor/parser/typeinfo.cpp
sources/shiboken6/ApiExtractor/parser/typeinfo.h
sources/shiboken6/ApiExtractor/predefined_templates.cpp
sources/shiboken6/ApiExtractor/propertyspec.cpp
sources/shiboken6/ApiExtractor/pymethoddefentry.h
sources/shiboken6/ApiExtractor/qtcompat.h
sources/shiboken6/ApiExtractor/qtdocparser.cpp
sources/shiboken6/ApiExtractor/qtdocparser.h
sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp
sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp
sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp
sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp
sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp
sources/shiboken6/ApiExtractor/tests/testcontainer.cpp
sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp
sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp
sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp
sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp
sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp
sources/shiboken6/ApiExtractor/tests/testenum.cpp
sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp
sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp
sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp
sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp
sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp
sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp
sources/shiboken6/ApiExtractor/tests/testnamespace.cpp
sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp
sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp
sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp
sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp
sources/shiboken6/ApiExtractor/tests/testremovefield.cpp
sources/shiboken6/ApiExtractor/tests/testremovefield.h
sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp
sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp
sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp
sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp
sources/shiboken6/ApiExtractor/tests/testtemplates.cpp
sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp
sources/shiboken6/ApiExtractor/tests/testutil.h
sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp
sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp
sources/shiboken6/ApiExtractor/textstream.h
sources/shiboken6/ApiExtractor/typedatabase.cpp
sources/shiboken6/ApiExtractor/typeparser.cpp
sources/shiboken6/ApiExtractor/typesystem.cpp
sources/shiboken6/ApiExtractor/typesystem_enums.h
sources/shiboken6/ApiExtractor/typesystem_typedefs.h
sources/shiboken6/ApiExtractor/typesystemparser.cpp
sources/shiboken6/ApiExtractor/typesystemparser_p.h
sources/shiboken6/ApiExtractor/typesystemtypeentry.h
sources/shiboken6/ApiExtractor/xmlutils_libxslt.cpp
sources/shiboken6/cmake/ShibokenHelpers.cmake
sources/shiboken6/doc/_static/css/qt_style.css
sources/shiboken6/doc/examples/index.rst
sources/shiboken6/doc/index.rst
sources/shiboken6/doc/shiboken-genpyi.rst [new file with mode: 0644]
sources/shiboken6/doc/shibokenmodule.rst
sources/shiboken6/doc/typediscovery.rst [new file with mode: 0644]
sources/shiboken6/doc/typesystem.rst
sources/shiboken6/doc/typesystem_codeinjection.rst
sources/shiboken6/doc/typesystem_converters.rst
sources/shiboken6/doc/typesystem_documentation.rst
sources/shiboken6/doc/typesystem_manipulating_objects.rst
sources/shiboken6/doc/typesystem_specifying_types.rst
sources/shiboken6/generator/generator.cpp
sources/shiboken6/generator/generator.h
sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
sources/shiboken6/generator/qtdoc/qtdocgenerator.h
sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp
sources/shiboken6/generator/shiboken/cppgenerator.cpp
sources/shiboken6/generator/shiboken/cppgenerator.h
sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
sources/shiboken6/generator/shiboken/ctypenames.h
sources/shiboken6/generator/shiboken/generatorstrings.h
sources/shiboken6/generator/shiboken/headergenerator.cpp
sources/shiboken6/generator/shiboken/headergenerator.h
sources/shiboken6/generator/shiboken/overloaddata.cpp
sources/shiboken6/generator/shiboken/pytypenames.h
sources/shiboken6/generator/shiboken/shibokengenerator.cpp
sources/shiboken6/generator/shiboken/shibokengenerator.h
sources/shiboken6/generators/shiboken/shiboken.cpp [deleted file]
sources/shiboken6/libshiboken/CMakeLists.txt
sources/shiboken6/libshiboken/autodecref.h
sources/shiboken6/libshiboken/basewrapper.cpp
sources/shiboken6/libshiboken/basewrapper.h
sources/shiboken6/libshiboken/bindingmanager.cpp
sources/shiboken6/libshiboken/bindingmanager.h
sources/shiboken6/libshiboken/helper.cpp
sources/shiboken6/libshiboken/helper.h
sources/shiboken6/libshiboken/pep384ext.h [new file with mode: 0644]
sources/shiboken6/libshiboken/pep384impl.cpp
sources/shiboken6/libshiboken/pep384impl.h
sources/shiboken6/libshiboken/pyobjectholder.h [new file with mode: 0644]
sources/shiboken6/libshiboken/sbkcontainer.h
sources/shiboken6/libshiboken/sbkconverter.cpp
sources/shiboken6/libshiboken/sbkconverter.h
sources/shiboken6/libshiboken/sbkconverter_p.h
sources/shiboken6/libshiboken/sbkcppstring.cpp
sources/shiboken6/libshiboken/sbkcppstring.h
sources/shiboken6/libshiboken/sbkcpptonumpy.cpp
sources/shiboken6/libshiboken/sbkenum.cpp
sources/shiboken6/libshiboken/sbkfeature_base.cpp
sources/shiboken6/libshiboken/sbkmodule.cpp
sources/shiboken6/libshiboken/sbkmodule.h
sources/shiboken6/libshiboken/sbknumpy.cpp
sources/shiboken6/libshiboken/sbknumpyarrayconverter.cpp
sources/shiboken6/libshiboken/sbkstaticstrings.cpp
sources/shiboken6/libshiboken/sbkstaticstrings.h
sources/shiboken6/libshiboken/sbktypefactory.cpp
sources/shiboken6/libshiboken/shiboken.h
sources/shiboken6/libshiboken/signature/signature.cpp
sources/shiboken6/libshiboken/signature/signature_extend.cpp
sources/shiboken6/libshiboken/signature/signature_helper.cpp
sources/shiboken6/libshiboken/voidptr.cpp
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/feature.py
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/fix-complaints.py
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/loader.py
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
sources/shiboken6/shibokenmodule/shibokenmodule.cpp [new file with mode: 0644]
sources/shiboken6/shibokenmodule/typesystem_shiboken.xml
sources/shiboken6/tests/dumpcodemodel/main.cpp
sources/shiboken6/tests/libother/othermultiplederived.h
sources/shiboken6/tests/libsample/abstract.cpp
sources/shiboken6/tests/libsample/abstract.h
sources/shiboken6/tests/libsample/derived.h
sources/shiboken6/tests/libsample/point.cpp
sources/shiboken6/tests/libsample/point.h
sources/shiboken6/tests/libsample/pointf.cpp
sources/shiboken6/tests/libsample/pointf.h
sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp
sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h
sources/shiboken6/tests/minimalbinding/brace_pattern_test.py
sources/shiboken6/tests/minimalbinding/listuser_test.py
sources/shiboken6/tests/minimalbinding/minbool_test.py
sources/shiboken6/tests/minimalbinding/obj_test.py
sources/shiboken6/tests/minimalbinding/typedef_test.py
sources/shiboken6/tests/minimalbinding/val_test.py
sources/shiboken6/tests/otherbinding/collector_external_operator_test.py
sources/shiboken6/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py
sources/shiboken6/tests/otherbinding/extended_multiply_operator_test.py
sources/shiboken6/tests/otherbinding/module_reload_test.py
sources/shiboken6/tests/otherbinding/new_ctor_operator_test.py
sources/shiboken6/tests/otherbinding/objtypehashes_test.py
sources/shiboken6/tests/otherbinding/otherderived_test.py
sources/shiboken6/tests/otherbinding/othertypesystypedef_test.py
sources/shiboken6/tests/otherbinding/signature_test.py
sources/shiboken6/tests/otherbinding/smartptr_test.py
sources/shiboken6/tests/otherbinding/star_import_test.py [new file with mode: 0644]
sources/shiboken6/tests/otherbinding/test_module_template.py
sources/shiboken6/tests/otherbinding/typediscovery_test.py
sources/shiboken6/tests/otherbinding/usersprimitivefromothermodule_test.py
sources/shiboken6/tests/otherbinding/wrongctor_test.py
sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp
sources/shiboken6/tests/samplebinding/__del___test.py
sources/shiboken6/tests/samplebinding/abstract_test.py
sources/shiboken6/tests/samplebinding/addedfunction_test.py
sources/shiboken6/tests/samplebinding/addedfunction_with_container_args_test.py
sources/shiboken6/tests/samplebinding/argumentmodifications_test.py
sources/shiboken6/tests/samplebinding/array_numpy_test.py
sources/shiboken6/tests/samplebinding/array_sequence_test.py
sources/shiboken6/tests/samplebinding/bug_554_test.py
sources/shiboken6/tests/samplebinding/bug_704_test.py
sources/shiboken6/tests/samplebinding/bytearray_test.py
sources/shiboken6/tests/samplebinding/child_return_test.py
sources/shiboken6/tests/samplebinding/class_fields_test.py
sources/shiboken6/tests/samplebinding/collector_test.py
sources/shiboken6/tests/samplebinding/complex_test.py
sources/shiboken6/tests/samplebinding/conversion_operator_test.py
sources/shiboken6/tests/samplebinding/copy_test.py
sources/shiboken6/tests/samplebinding/ctorconvrule_test.py
sources/shiboken6/tests/samplebinding/cyclic_test.py
sources/shiboken6/tests/samplebinding/date_test.py
sources/shiboken6/tests/samplebinding/decisor_test.py
sources/shiboken6/tests/samplebinding/delete_test.py
sources/shiboken6/tests/samplebinding/deprecated_test.py
sources/shiboken6/tests/samplebinding/derived_test.py
sources/shiboken6/tests/samplebinding/duck_punching_test.py
sources/shiboken6/tests/samplebinding/echo_test.py
sources/shiboken6/tests/samplebinding/enum_test.py
sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py
sources/shiboken6/tests/samplebinding/event_loop_call_virtual_test.py
sources/shiboken6/tests/samplebinding/event_loop_thread_test.py
sources/shiboken6/tests/samplebinding/exception_test.py
sources/shiboken6/tests/samplebinding/filter_test.py
sources/shiboken6/tests/samplebinding/handleholder_test.py
sources/shiboken6/tests/samplebinding/hashabletype_test.py
sources/shiboken6/tests/samplebinding/ignorederefop_test.py
sources/shiboken6/tests/samplebinding/implicitconv_numerical_test.py
sources/shiboken6/tests/samplebinding/implicitconv_test.py
sources/shiboken6/tests/samplebinding/inheritanceandscope_test.py
sources/shiboken6/tests/samplebinding/injectcode_test.py
sources/shiboken6/tests/samplebinding/innerclass_test.py
sources/shiboken6/tests/samplebinding/intlist_test.py
sources/shiboken6/tests/samplebinding/intwrapper_test.py
sources/shiboken6/tests/samplebinding/invalid_virtual_return_test.py
sources/shiboken6/tests/samplebinding/keep_reference_test.py
sources/shiboken6/tests/samplebinding/list_test.py
sources/shiboken6/tests/samplebinding/lock_test.py
sources/shiboken6/tests/samplebinding/map_test.py
sources/shiboken6/tests/samplebinding/metaclass_test.py
sources/shiboken6/tests/samplebinding/mixed_mi_test.py
sources/shiboken6/tests/samplebinding/modelindex_test.py
sources/shiboken6/tests/samplebinding/modelview_test.py
sources/shiboken6/tests/samplebinding/modifications_test.py
sources/shiboken6/tests/samplebinding/modified_constructor_test.py
sources/shiboken6/tests/samplebinding/modifiedvirtualmethods_test.py
sources/shiboken6/tests/samplebinding/multi_cpp_inheritance_test.py
sources/shiboken6/tests/samplebinding/multiple_derived_test.py
sources/shiboken6/tests/samplebinding/namespace_test.py
sources/shiboken6/tests/samplebinding/newdivision_test.py
sources/shiboken6/tests/samplebinding/nondefaultctor_test.py
sources/shiboken6/tests/samplebinding/nontypetemplate_test.py
sources/shiboken6/tests/samplebinding/nonzero_test.py
sources/shiboken6/tests/samplebinding/numericaltypedef_test.py
sources/shiboken6/tests/samplebinding/numpy_test.py
sources/shiboken6/tests/samplebinding/objecttype_test.py
sources/shiboken6/tests/samplebinding/objecttype_with_named_args_test.py
sources/shiboken6/tests/samplebinding/objecttypebyvalue_test.py
sources/shiboken6/tests/samplebinding/objecttypelayout_test.py
sources/shiboken6/tests/samplebinding/objecttypeoperators_test.py
sources/shiboken6/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py
sources/shiboken6/tests/samplebinding/oddbool_test.py
sources/shiboken6/tests/samplebinding/onlycopyclass_test.py
sources/shiboken6/tests/samplebinding/overflow_test.py
sources/shiboken6/tests/samplebinding/overload_sorting_test.py
sources/shiboken6/tests/samplebinding/overload_test.py
sources/shiboken6/tests/samplebinding/overloadwithdefault_test.py
sources/shiboken6/tests/samplebinding/ownership_argument_invalidation_test.py
sources/shiboken6/tests/samplebinding/ownership_delete_child_in_cpp_test.py
sources/shiboken6/tests/samplebinding/ownership_delete_child_in_python_test.py
sources/shiboken6/tests/samplebinding/ownership_delete_parent_test.py
sources/shiboken6/tests/samplebinding/ownership_invalidate_after_use_test.py
sources/shiboken6/tests/samplebinding/ownership_invalidate_child_test.py
sources/shiboken6/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py
sources/shiboken6/tests/samplebinding/ownership_invalidate_parent_test.py
sources/shiboken6/tests/samplebinding/ownership_reparenting_test.py
sources/shiboken6/tests/samplebinding/ownership_transference_test.py
sources/shiboken6/tests/samplebinding/pair_test.py
sources/shiboken6/tests/samplebinding/pen_test.py
sources/shiboken6/tests/samplebinding/point_test.py
sources/shiboken6/tests/samplebinding/pointerholder_test.py
sources/shiboken6/tests/samplebinding/pointerprimitivetype_test.py
sources/shiboken6/tests/samplebinding/pointf_test.py
sources/shiboken6/tests/samplebinding/primitivereferenceargument_test.py
sources/shiboken6/tests/samplebinding/privatector_test.py
sources/shiboken6/tests/samplebinding/privatedtor_test.py
sources/shiboken6/tests/samplebinding/protected_test.py
sources/shiboken6/tests/samplebinding/pstrlist_test.py
sources/shiboken6/tests/samplebinding/pystr_test.py
sources/shiboken6/tests/samplebinding/python_thread_test.py
sources/shiboken6/tests/samplebinding/receive_null_cstring_test.py
sources/shiboken6/tests/samplebinding/reference_test.py
sources/shiboken6/tests/samplebinding/referencetopointer_test.py
sources/shiboken6/tests/samplebinding/renaming_test.py
sources/shiboken6/tests/samplebinding/return_null_test.py
sources/shiboken6/tests/samplebinding/richcompare_test.py
sources/shiboken6/tests/samplebinding/sample_test.py
sources/shiboken6/tests/samplebinding/simplefile_test.py
sources/shiboken6/tests/samplebinding/size_test.py
sources/shiboken6/tests/samplebinding/static_nonstatic_methods_test.py
sources/shiboken6/tests/samplebinding/str_test.py
sources/shiboken6/tests/samplebinding/strlist_test.py
sources/shiboken6/tests/samplebinding/templateinheritingclass_test.py
sources/shiboken6/tests/samplebinding/time_test.py
sources/shiboken6/tests/samplebinding/transform_test.py
sources/shiboken6/tests/samplebinding/typeconverters_test.py
sources/shiboken6/tests/samplebinding/typedealloc_test.py
sources/shiboken6/tests/samplebinding/typedtordoublefree_test.py
sources/shiboken6/tests/samplebinding/typesystem_sample.xml
sources/shiboken6/tests/samplebinding/typesystypedef_test.py
sources/shiboken6/tests/samplebinding/unsafe_parent_test.py
sources/shiboken6/tests/samplebinding/useraddedctor_test.py
sources/shiboken6/tests/samplebinding/virtualdtor_test.py
sources/shiboken6/tests/samplebinding/virtualmethods_test.py
sources/shiboken6/tests/samplebinding/visibilitychange_test.py
sources/shiboken6/tests/samplebinding/voidholder_test.py
sources/shiboken6/tests/samplebinding/weakref_test.py
sources/shiboken6/tests/samplebinding/writableclassdict_test.py
sources/shiboken6/tests/shibokenmodule/module_test.py
sources/shiboken6/tests/smartbinding/CMakeLists.txt
sources/shiboken6/tests/smartbinding/smart_pointer_test.py
sources/shiboken6/tests/smartbinding/std_optional_test.py
sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py
sources/shiboken6/tests/smartbinding/std_unique_ptr_test.py
sources/shiboken6/tests/smartbinding/typesystem_smart.xml
testing/wheel_tester.py
tools/create_changelog.py
tools/cross_compile_android/android_utilities.py
tools/cross_compile_android/main.py
tools/cross_compile_android/templates/cross_compile.tmpl.sh
tools/cross_compile_android/templates/toolchain_default.tmpl.cmake
tools/example_gallery/main.py
tools/snippets_translate/module_classes.py
wheel_artifacts/pyproject.toml.base

diff --git a/.flake8 b/.flake8
index ef866035bb7989150f5721750bb21da04f451c0d..f7b40d7487fd41321ba8829a02ed2edd282cfc07 100644 (file)
--- a/.flake8
+++ b/.flake8
@@ -5,5 +5,8 @@ exclude = rc_*.py,*_rc.py,ui_*.py
 per-file-ignores =
     # for init_test_paths() hack
     *_test_*.py:E402
+    *_test.py:E402
+    *bug_*.py:E402
+    test_*.py:E402
+    signal_across_threads.py:E402
     __init__.py:F401,E402
-
diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt
new file mode 100644 (file)
index 0000000..136d900
--- /dev/null
@@ -0,0 +1,61 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+    1. Definitions.
+
+        "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+        "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+        "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+        "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+        "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+        "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+        "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+        "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+        "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+        "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+    2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+    3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+    4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+        (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+        (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+        (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+        (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+        You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+    5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+    6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+    7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+    8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+    9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
index cdeb0398bc2adcc243f81c76573b1c36019e0810..35f5a9063140a260c52de9df9272d9e0ef59a11b 100644 (file)
--- a/README.md
+++ b/README.md
@@ -118,7 +118,7 @@ using `setup.py build`:
 
 ## Requirements
 
- * Python 3.8+ is supported (for Qt 6.6+)
+ * Python 3.9+ is supported (for Qt 6.7+)
  * CMake: Specify the path to cmake with `--cmake` option or add cmake to the
    system path.
  * Qt 6.x is supported. Specify the path to qtpaths with `--qtpaths` option or
index 8c70b1c8f6f6fa8c83d1be0ffbafe3daf987d4d9..9178660d5118c9b70b4e2a6002e91ddcec2264d7 100644 (file)
@@ -88,7 +88,7 @@ and [join our community](https://wiki.qt.io/Qt_for_Python#Community)!
 
 ### Licensing
 
-PySide6 is available under both Open Source (LGPLv3/GPLv2) and commercial
+PySide6 is available under both Open Source (LGPLv3/GPLv3) and commercial
 license. Using PyPi is the recommended installation source, because the
 content of the wheels is valid for both cases. For more information, refer to
 the [Qt Licensing page](https://www.qt.io/licensing/).
index 3247a550d66471f220c80354687d264cf7812ed9..e6044c4a4c86b0074481e3aef611db315c7cea67 100644 (file)
@@ -65,7 +65,7 @@ and [join our community](https://wiki.qt.io/Qt_for_Python#Community)!
 
 ### Licensing
 
-PySide6 is available under both Open Source (LGPLv3/GPLv2) and commercial
+PySide6 is available under both Open Source (LGPLv3/GPLv3) and commercial
 license. Using PyPi is the recommended installation source, because the
 content of the wheels is valid for both cases. For more information, refer to
 the [Qt Licensing page](https://www.qt.io/licensing/).
index b23ce8903676183a0fe83dda5d9a75a70ffec34a..7f96c19b117b416347b5cfd38e844679ff97ac33 100644 (file)
@@ -26,6 +26,7 @@ it includes only the essentials Qt modules:
 * QtQml
 * QtQuick
 * QtQuickControls2
+* QtQuickTest
 * QtQuickWidgets
 * QtXml
 * QtTest
@@ -50,7 +51,7 @@ and [join our community](https://wiki.qt.io/Qt_for_Python#Community)!
 
 ### Licensing
 
-PySide6 is available under both Open Source (LGPLv3/GPLv2) and commercial
+PySide6 is available under both Open Source (LGPLv3/GPLv3) and commercial
 license. Using PyPi is the recommended installation source, because the
 content of the wheels is valid for both cases. For more information, refer to
 the [Qt Licensing page](https://www.qt.io/licensing/).
index ffa7d83d5a86dc3a3d7daa3051ae5b72579991e0..15e3181514974ac741a7bcb96b4d85626b56270a 100644 (file)
@@ -28,7 +28,7 @@ and [join our community](https://wiki.qt.io/Qt_for_Python#Community)!
 
 ### Licensing
 
-PySide6 is available under both Open Source (LGPLv3/GPLv2) and commercial
+PySide6 is available under both Open Source (LGPLv3/GPLv3) and commercial
 licenses. Using PyPi is the recommended installation source, because the
 content of the wheels is valid for both cases. For more information, refer to
 the [Qt Licensing page](https://www.qt.io/licensing/).
index de28b82b63d133669552acf535efae8a1f7a681b..128bb2394c29fcf6013697519ba08edf36b5df2a 100644 (file)
@@ -17,7 +17,10 @@ PYSIDE_UNIX_BIN_TOOLS = ["lupdate",
                          "lrelease",
                          "qmllint",
                          "qmlformat",
-                         "qmlls"]
+                         "qmlls",
+                         "qsb",
+                         "balsam",
+                         "balsamui"]
 
 # tools that are bundled as .app in macOS, but are normal executables in Linux and Windows
 PYSIDE_UNIX_BUNDLED_TOOLS = ["assistant",
index a073fb70773352f62ffa609421903a7a79b39e14..30ce187c817cfe09682c2572cc32f1dde407b510 100644 (file)
@@ -104,7 +104,7 @@ def _get_py_library_unix(build_type, py_version, py_prefix, py_libdir,
     if hasattr(sys, "pypy_version_info"):
         vi = sys.version_info[:2]
         version_quirk = ".".join(map(str, vi)) if vi >= (3, 9) else "3"
-        pypy_libdir = Path(py_libdir).parent /  "bin"
+        pypy_libdir = Path(py_libdir).parent / "bin"
         for lib_ext in lib_exts:
             lib_name = f"libpypy{version_quirk}-c{lib_ext}"
             pypy_library = pypy_libdir / lib_name
index 5a711f445acc0056f9557c8257c00bcbc570ca76..0a6eebf7801cb6ddfdc4cdf2abaefa63f9097bf7 100644 (file)
@@ -61,7 +61,6 @@ class Config(object):
         self.python_version_classifiers = [
             'Programming Language :: Python',
             'Programming Language :: Python :: 3',
-            'Programming Language :: Python :: 3.8',
             'Programming Language :: Python :: 3.9',
             'Programming Language :: Python :: 3.10',
             'Programming Language :: Python :: 3.11',
@@ -116,7 +115,7 @@ class Config(object):
         setup_kwargs['zip_safe'] = False
         setup_kwargs['cmdclass'] = cmd_class_dict
         setup_kwargs['version'] = package_version
-        setup_kwargs['python_requires'] = ">=3.8, <3.13"
+        setup_kwargs['python_requires'] = ">=3.9, <3.13"
 
         if log_level == LogLevel.QUIET:
             # Tells setuptools to be quiet, and only print warnings or errors.
index 16e4cca2099976e702d9b577961955889260a893..c9ccf3fb9c883a8bc329f582cf9bcf0242a5e0b9 100644 (file)
@@ -8,8 +8,8 @@ from enum import Enum
 logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)
 log = logging.getLogger("qtforpython")
 
+
 class LogLevel(Enum):
     QUIET = 1
     INFO = 2
     VERBOSE = 3
-
index cc77c40bb0406429f452b5094be02588e4614d59..bf71f9962240baa096041737896807a91938d792 100644 (file)
@@ -10,7 +10,7 @@ import sysconfig
 import time
 from packaging.version import parse as parse_version
 from pathlib import Path
-from shutil import copytree
+from shutil import copytree, rmtree
 from textwrap import dedent
 
 # PYSIDE-1760: Pre-load setuptools modules early to avoid racing conditions.
@@ -690,7 +690,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
         else:
             raise SetupError("option limited-api must be 'yes' or 'no' "
                              "(default yes if applicable, i.e. Python "
-                             "version >= 3.8 and release build if on Windows)")
+                             "version >= 3.9 and release build if on Windows)")
 
         if OPTION["DISABLE_PYI"]:
             cmake_cmd.append("-DDISABLE_PYI=yes")
@@ -741,7 +741,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
         cmake_cmd.append(f"-DPACKAGE_SETUP_PY_PACKAGE_TIMESTAMP={timestamp}")
 
         if extension.lower() in [SHIBOKEN]:
-            cmake_cmd.append("-DUSE_PYTHON_VERSION=3.8")
+            cmake_cmd.append("-DUSE_PYTHON_VERSION=3.9")
 
         cmake_cmd += platform_cmake_options()
 
@@ -783,7 +783,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
             os.environ['MACOSX_DEPLOYMENT_TARGET'] = deployment_target
 
         if OPTION["BUILD_DOCS"]:
-            # Build the whole documentation (rst + API) by default
+            # Build the whole documentation (Base + API) by default
             cmake_cmd.append("-DFULLDOCSBUILD=1")
 
             if OPTION["DOC_BUILD_ONLINE"]:
@@ -1195,17 +1195,21 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
             log.debug(f"Patched rpath to '{rpath_value}' in {library}.")
 
 
-class PysideRstDocs(Command, CommandMixin):
-    description = "Build .rst documentation only"
+class PysideBaseDocs(Command, CommandMixin):
+    description = "Build the base documentation only"
     user_options = CommandMixin.mixin_user_options
 
     def __init__(self, *args, **kwargs):
-        self.command_name = "build_rst_docs"
+        if args[0].commands[0] == "build_rst_docs":
+            args[0].commands[0] = "build_base_docs"
+            log.warning("'build_rst_docs' is deprecated and will be removed. "
+                        "Please use 'build_base_docs' instead.")
+        self.command_name = "build_base_docs"
         Command.__init__(self, *args, **kwargs)
         CommandMixin.__init__(self)
 
     def initialize_options(self):
-        log.info("-- This build process will not include the API documentation."
+        log.info("-- This build process will not include the API documentation. "
                  "API documentation requires a full build of pyside/shiboken.")
         self.skip = False
         if config.is_internal_shiboken_generator_build():
@@ -1215,8 +1219,13 @@ class PysideRstDocs(Command, CommandMixin):
             self.doc_dir = config.setup_script_dir / "sources" / self.name / "doc"
             # Check if sphinx is installed to proceed.
             found = importlib.util.find_spec("sphinx")
+            self.html_dir = Path("html")
             if found:
                 if self.name == SHIBOKEN:
+                    # Delete the 'html' directory since new docs will be generated anyway
+                    if self.html_dir.is_dir():
+                        rmtree(self.html_dir)
+                        log.info("-- Deleted old html directory")
                     log.info("-- Generating Shiboken documentation")
                     log.info(f"-- Documentation directory: 'html/{PYSIDE}/{SHIBOKEN}/'")
                 elif self.name == PYSIDE:
@@ -1224,7 +1233,6 @@ class PysideRstDocs(Command, CommandMixin):
                     log.info(f"-- Documentation directory: 'html/{PYSIDE}/'")
             else:
                 raise SetupError("Sphinx not found - aborting")
-            self.html_dir = Path("html")
 
             # creating directories html/pyside6/shiboken6
             try:
@@ -1272,7 +1280,7 @@ class PysideRstDocs(Command, CommandMixin):
                 raise SetupError(f"Error running CMake for {self.doc_dir}")
 
             if self.name == PYSIDE:
-                self.sphinx_src = self.out_dir / "rst"
+                self.sphinx_src = self.out_dir / "base"
                 example_gallery = config.setup_script_dir / "tools" / "example_gallery" / "main.py"
                 assert example_gallery.is_file()
                 example_gallery_cmd = [sys.executable, os.fspath(example_gallery)]
@@ -1307,7 +1315,9 @@ cmd_class_dict = {
     'develop': PysideDevelop,
     'install': PysideInstall,
     'install_lib': PysideInstallLib,
-    'build_rst_docs': PysideRstDocs,
+    'build_base_docs': PysideBaseDocs,
+    # TODO: Remove build_rst_docs in the next version, see PYSIDE-2504
+    'build_rst_docs': PysideBaseDocs,
 }
 if wheel_module_exists:
     pyside_bdist_wheel = get_bdist_wheel_override()
index 6c6acd5882e7976dc0c48b6bfc52284a0b97d4b5..bfaf03262069622bac018c029ba9a554cb7864f3 100644 (file)
@@ -123,7 +123,8 @@ def _jobs_option_value():
 
 def find_qtpaths():
     # for these command --qtpaths should not be required
-    no_qtpaths_commands = ["--help", "--help-commands", "--qt-target-path", "build_rst_docs"]
+    no_qtpaths_commands = ["--help", "--help-commands", "--qt-target-path", "build_base_docs",
+                           "build_rst_docs"]
 
     for no_qtpaths_command in no_qtpaths_commands:
         if any(no_qtpaths_command in argument for argument in sys.argv):
@@ -244,7 +245,8 @@ class CommandMixin(object):
         # We redeclare plat-name as an option so it's recognized by the
         # install command and doesn't throw an error.
         ('plat-name=', None, 'The platform name for which we are cross-compiling'),
-        ('unity', None, 'Use CMake UNITY_BUILD_MODE'),
+        ('unity', None, 'Use CMake UNITY_BUILD_MODE (obsolete)'),
+        ('no-unity', None, 'Disable CMake UNITY_BUILD_MODE'),
         ('unity-build-batch-size=', None, 'Value of CMAKE_UNITY_BUILD_BATCH_SIZE')
     ]
 
@@ -305,6 +307,7 @@ class CommandMixin(object):
         self.internal_cmake_install_dir_query_file_path = None
         self._per_command_mixin_options_finalized = False
         self.unity = False
+        self.no_unity = False
         self.unity_build_batch_size = "16"
 
         # When initializing a command other than the main one (so the
@@ -369,7 +372,8 @@ class CommandMixin(object):
         OPTION['NO_STRIP'] = self.no_strip
         OPTION['ONLYPACKAGE'] = self.only_package
         OPTION['STANDALONE'] = self.standalone
-        OPTION['IGNOREGIT'] = self.ignore_git
+        if self.ignore_git:
+            _warn_deprecated_option('ignore_git')
         OPTION['SKIP_DOCS'] = self.skip_docs
         OPTION['BUILD_DOCS'] = self.build_docs
         OPTION['BUILDTESTS'] = self.build_tests
@@ -392,8 +396,8 @@ class CommandMixin(object):
 
         # By default they are False, so we check if they changed with xor
         if bool(OPTION["QUIET"]) != bool(OPTION["VERBOSE_BUILD"]):
-            log.warn("Using --quiet and --verbose-build is deprecated. "
-                     "Please use --log-level=quiet or --log-level=verbose instead.")
+            log.warning("Using --quiet and --verbose-build is deprecated. "
+                        "Please use --log-level=quiet or --log-level=verbose instead.")
             # We assign a string value instead of the enum
             # because is what we get from the command line.
             # Later we assign the enum
@@ -420,7 +424,10 @@ class CommandMixin(object):
         OPTION['SANITIZE_ADDRESS'] = self.sanitize_address
         OPTION['SHORTER_PATHS'] = self.shorter_paths
         OPTION['DOC_BUILD_ONLINE'] = self.doc_build_online
-        OPTION['UNITY'] = self.unity
+        if self.unity:
+            log.warning("Using --unity no longer has any effect, "
+                        "Unity build mode is now the default.")
+        OPTION['UNITY'] = not self.no_unity
         OPTION['UNITY_BUILD_BATCH_SIZE'] = self.unity_build_batch_size
 
         qtpaths_abs_path = None
@@ -454,7 +461,7 @@ class CommandMixin(object):
                        qt_target_path=qt_target_path,
                        cmake_toolchain_file=cmake_toolchain_file)
 
-        if 'build_rst_docs' not in sys.argv:
+        if 'build_base_docs' not in sys.argv and 'build_rst_docs' not in sys.argv:
             try:
                 QtInfo().prefix_dir
             except Exception as e:
@@ -542,8 +549,10 @@ class CommandMixin(object):
         # We also don't do auto-searching if qt-target-path is passed
         # explicitly. This is to help with the building of host tools
         # while cross-compiling.
-        # Skip this process for the 'build_rst_docs' command
-        if not (self.is_cross_compile and not self.qt_target_path
+        # Skip this process for the 'build_base_docs' command
+        if (not self.is_cross_compile
+                and not self.qt_target_path
+                and 'build_base_docs' not in sys.argv
                 and 'build_rst_docs' not in sys.argv):
             # Enforce usage of qmake in QtInfo if it was given explicitly.
             if self.qmake:
index cb388e8aaefb35c392a8c4f7d89520b188209a15..b4c66d94ed214ce0d14aaa52aa185ed47cc3ce57 100644 (file)
@@ -95,7 +95,7 @@ def prepare_standalone_package_linux(pyside_build, _vars, cross_build=False, is_
                 _filter=["*.so"],
                 recursive=True,
                 _vars=_vars)
-        if not is_pypy:
+        if not is_pypy and not is_android:
             copydir("{install_dir}/plugins/designer",
                     plugins_target / "designer",
                     _filter=["*.so"],
index 17c4ba34f98dc30b0fc2e488e83e480c1d3aa226..3333f5f96462ca9d55102355ce89a1c4cd28487b 100644 (file)
@@ -122,7 +122,7 @@ def prepare_packages_posix(pyside_build, _vars, cross_build=False):
             scripts = ["pyside_tool.py", "metaobjectdump.py", "project.py", "qml.py",
                        "qtpy2cpp.py", "deploy.py"]
 
-            script_dirs = ["qtpy2cpp_lib", "deploy_lib",  "project"]
+            script_dirs = ["qtpy2cpp_lib", "deploy_lib", "project"]
 
             if sys.platform.startswith("linux"):
                 scripts.append("android_deploy.py")
@@ -170,10 +170,10 @@ def prepare_packages_posix(pyside_build, _vars, cross_build=False):
                 lib_exec_filters.append('QtWebEngineProcess')
             if lib_exec_filters:
                 libexec_executables.extend(copydir("{qt_lib_execs_dir}",
-                                                destination_qt_dir / "libexec",
-                                                _filter=lib_exec_filters,
-                                                recursive=False,
-                                                _vars=_vars))
+                                                   destination_qt_dir / "libexec",
+                                                   _filter=lib_exec_filters,
+                                                   recursive=False,
+                                                   _vars=_vars))
 
         # <install>/lib/lib* -> {st_package_name}/
         copydir(
@@ -214,7 +214,7 @@ def prepare_packages_posix(pyside_build, _vars, cross_build=False):
         # <source>/pyside6/{st_package_name}/QtAsyncio/* ->
         #   <setup>/{st_package_name}/QtAsyncio/*
         copydir(
-            f"{{site_packages_dir}}/{{st_package_name}}/QtAsyncio",
+            "{site_packages_dir}/{st_package_name}/QtAsyncio",
             "{st_build_dir}/{st_package_name}/QtAsyncio",
             _vars=_vars)
 
index c3b19d5a198641b5e2f86088f968cade32b62360..9c29953be2acdbe6c4c4b4f62db2df4023f034fb 100644 (file)
@@ -167,7 +167,7 @@ def prepare_packages_win32(pyside_build, _vars):
         # <source>/pyside6/{st_package_name}/QtAsyncio/* ->
         #   <setup>/{st_package_name}/QtAsyncio/*
         copydir(
-            f"{{site_packages_dir}}/{{st_package_name}}/QtAsyncio",
+            "{site_packages_dir}/{st_package_name}/QtAsyncio",
             "{st_build_dir}/{st_package_name}/QtAsyncio",
             _vars=_vars)
 
@@ -288,6 +288,11 @@ def copy_qt_artifacts(pyside_build, destination_qt_dir, copy_pdbs, _vars):
 
     # <qt>/bin/*.dll and Qt *.exe -> <setup>/{st_package_name}
     qt_artifacts_permanent = [
+        "avcodec-60.dll",
+        "avformat-60.dll",
+        "avutil-58.dll",
+        "swresample-4.dll",
+        "swscale-7.dll",
         "opengl*.dll",
         "designer.exe",
         "linguist.exe",
diff --git a/build_scripts/qfp_tool.py b/build_scripts/qfp_tool.py
new file mode 100644 (file)
index 0000000..abaf48f
--- /dev/null
@@ -0,0 +1,457 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import datetime
+import os
+import re
+import subprocess
+import sys
+import time
+import warnings
+from argparse import ArgumentParser, RawTextHelpFormatter
+from enum import Enum, auto
+from pathlib import Path
+from typing import List
+
+DESC = """
+Utility script for working with Qt for Python.
+
+Feel free to extend!
+
+Typical Usage:
+Update and build a repository: python qfp_tool -p -b
+
+qfp_tool.py uses a configuration file "%CONFIGFILE%"
+in the format key=value.
+
+It is possible to use repository-specific values by adding a key postfixed by
+a dash and the repository folder base name, eg:
+Modules-pyside-setup512=Core,Gui,Widgets,Network,Test
+
+Configuration keys:
+Acceleration     Incredibuild or unset
+BuildArguments   Arguments to setup.py
+Generator        Generator to be used for CMake. Currently, only Ninja is
+                 supported.
+Jobs             Number of jobs to be run simultaneously
+Modules          Comma separated list of modules to be built
+                 (for --module-subset=)
+Python           Python executable (Use python_d for debug builds on Windows)
+
+Arbitrary keys can be defined and referenced by $(name):
+
+MinimalModules=Core,Gui,Widgets,Network,Test
+Modules=$(MinimalModules),Multimedia
+Modules-pyside-setup-minimal=$(MinimalModules)
+"""
+
+
+class Acceleration(Enum):
+    NONE = 0
+    INCREDIBUILD = 1
+
+
+class BuildMode(Enum):
+    NONE = 0
+    BUILD = 1
+    RECONFIGURE = 2
+    MAKE = 3
+
+
+class UnityMode(Enum):
+    DEFAULT = auto()
+    ENABLE = auto()
+    DISABLE = auto()
+
+
+DISABLE_UNITY_OPTION = "--no-unity"
+LOG_LEVEL_OPTION = "--log-level"
+DEFAULT_BUILD_ARGS = ['--build-tests', '--skip-docs', LOG_LEVEL_OPTION, "quiet"]
+IS_WINDOWS = sys.platform == 'win32'
+INCREDIBUILD_CONSOLE = 'BuildConsole' if IS_WINDOWS else '/opt/incredibuild/bin/ib_console'
+# Config file keys
+ACCELERATION_KEY = 'Acceleration'
+BUILDARGUMENTS_KEY = 'BuildArguments'
+GENERATOR_KEY = 'Generator'
+JOBS_KEY = 'Jobs'
+MODULES_KEY = 'Modules'
+PYTHON_KEY = 'Python'
+
+DEFAULT_MODULES = "Core,Gui,Widgets,Network,Test,Qml,Quick,Multimedia,MultimediaWidgets"
+DEFAULT_CONFIG_FILE = f"Modules={DEFAULT_MODULES}\n"
+
+build_mode = BuildMode.NONE
+opt_dry_run = False
+opt_verbose = False
+opt_unity_mode = UnityMode.DEFAULT
+
+
+def which(needle: str):
+    """Perform a path search"""
+    needles = [needle]
+    if IS_WINDOWS:
+        for ext in ("exe", "bat", "cmd"):
+            needles.append(f"{needle}.{ext}")
+
+    for path in os.environ.get("PATH", "").split(os.pathsep):
+        for n in needles:
+            binary = Path(path) / n
+            if binary.is_file():
+                return binary
+    return None
+
+
+def command_log_string(args: List[str], directory: Path):
+    result = f'[{directory.name}]'
+    for arg in args:
+        result += f' "{arg}"' if ' ' in arg else f' {arg}'
+    return result
+
+
+def execute(args: List[str]):
+    """Execute a command and print to log"""
+    log_string = command_log_string(args, Path.cwd())
+    print(log_string)
+    if opt_dry_run:
+        return
+    exit_code = subprocess.call(args)
+    if exit_code != 0:
+        raise RuntimeError(f'FAIL({exit_code}): {log_string}')
+
+
+def run_process_output(args):
+    """Run a process and return its output. Also run in dry_run mode"""
+    std_out = subprocess.Popen(args, universal_newlines=1,
+                               stdout=subprocess.PIPE).stdout
+    result = [line.rstrip() for line in std_out.readlines()]
+    std_out.close()
+    return result
+
+
+def run_git(args):
+    """Run git in the current directory and its submodules"""
+    args.insert(0, git)  # run in repo
+    execute(args)  # run for submodules
+
+
+def expand_reference(cache_dict, value):
+    """Expand references to other keys in config files $(name) by value."""
+    pattern = re.compile(r"\$\([^)]+\)")
+    while True:
+        match = pattern.match(value)
+        if not match:
+            break
+        key = match.group(0)[2:-1]
+        value = value[:match.start(0)] + cache_dict[key] + value[match.end(0):]
+    return value
+
+
+def editor():
+    editor = os.getenv('EDITOR')
+    if not editor:
+        return 'notepad' if IS_WINDOWS else 'vi'
+    editor = editor.strip()
+    if IS_WINDOWS:
+        # Windows: git requires quotes in the variable
+        if editor.startswith('"') and editor.endswith('"'):
+            editor = editor[1:-1]
+        editor = editor.replace('/', '\\')
+    return editor
+
+
+def edit_config_file():
+    exit_code = -1
+    try:
+        exit_code = subprocess.call([editor(), config_file])
+    except Exception as e:
+        reason = str(e)
+        print(f'Unable to launch: {editor()}: {reason}')
+    return exit_code
+
+
+"""
+Config file handling, cache and read function
+"""
+config_dict = {}
+
+
+def read_config_file(file_name):
+    """Read the config file into config_dict, expanding continuation lines"""
+    global config_dict
+    keyPattern = re.compile(r'^\s*([A-Za-z0-9\_\-]+)\s*=\s*(.*)$')
+    with open(file_name) as f:
+        while True:
+            line = f.readline()
+            if not line:
+                break
+            line = line.rstrip()
+            match = keyPattern.match(line)
+            if match:
+                key = match.group(1)
+                value = match.group(2)
+                while value.endswith('\\'):
+                    value = value.rstrip('\\')
+                    value += f.readline().rstrip()
+                config_dict[key] = expand_reference(config_dict, value)
+
+
+def read_config(key):
+    """
+    Read a value from the '$HOME/.qfp_tool' configuration file. When given
+    a key 'key' for the repository directory '/foo/qt-5', check for the
+    repo-specific value 'key-qt5' and then for the general 'key'.
+    """
+    if not config_dict:
+        read_config_file(config_file)
+    repo_value = config_dict.get(f"{key}-{base_dir}")
+    return repo_value if repo_value else config_dict.get(key)
+
+
+def read_bool_config(key):
+    value = read_config(key)
+    return value and value in ['1', 'true', 'True']
+
+
+def read_int_config(key, default=-1):
+    value = read_config(key)
+    return int(value) if value else default
+
+
+def read_acceleration_config():
+    value = read_config(ACCELERATION_KEY)
+    if value:
+        value = value.lower()
+        if value == 'incredibuild':
+            return Acceleration.INCREDIBUILD
+    return Acceleration.NONE
+
+
+def read_config_build_arguments():
+    value = read_config(BUILDARGUMENTS_KEY)
+    if value:
+        return re.split(r'\s+', value)
+    return DEFAULT_BUILD_ARGS
+
+
+def read_config_modules_argument():
+    value = read_config(MODULES_KEY)
+    if value and value != '' and value != 'all':
+        return f"--module-subset={value}"
+    return None
+
+
+def read_config_python_binary() -> str:
+    binary = read_config(PYTHON_KEY)
+    virtual_env = os.environ.get('VIRTUAL_ENV')
+    if not binary:
+        # Use 'python3' unless virtualenv is set
+        use_py3 = not virtual_env and which('python3')
+        binary = 'python3' if use_py3 else 'python'
+    binary = Path(binary)
+    if not binary.is_absolute():
+        abs_path = which(str(binary))
+        if abs_path:
+            binary = abs_path
+        else:
+            warnings.warn(f'Unable to find "{binary}"', RuntimeWarning)
+    if virtual_env:
+        if not str(binary).startswith(virtual_env):
+            w = f'Python "{binary}" is not under VIRTUAL_ENV "{virtual_env}"'
+            warnings.warn(w, RuntimeWarning)
+    return str(binary)
+
+
+def get_config_file(base_name) -> Path:
+    global user
+    home = os.getenv('HOME')
+    if IS_WINDOWS:
+        # Set a HOME variable on Windows such that scp. etc.
+        # feel at home (locating .ssh).
+        if not home:
+            home = os.getenv('HOMEDRIVE') + os.getenv('HOMEPATH')
+            os.environ['HOME'] = home
+        user = os.getenv('USERNAME')
+        config_file = Path(os.getenv('APPDATA')) / base_name
+    else:
+        user = os.getenv('USER')
+        config_dir = Path(home) / '.config'
+        if config_dir.exists():
+            config_file = config_dir / base_name
+        else:
+            config_file = Path(home) / f".{base_name}"
+    return config_file
+
+
+def build(target: str):
+    """Run configure and build steps"""
+    start_time = time.time()
+
+    arguments = []
+    acceleration = read_acceleration_config()
+    if not IS_WINDOWS and acceleration == Acceleration.INCREDIBUILD:
+        arguments.append(INCREDIBUILD_CONSOLE)
+        arguments.appendh('--avoid')  # caching, v0.96.74
+    arguments.extend([read_config_python_binary(), 'setup.py', target])
+    build_arguments = read_config_build_arguments()
+    if opt_verbose and LOG_LEVEL_OPTION in build_arguments:
+        i = build_arguments.index(LOG_LEVEL_OPTION)
+        del build_arguments[i]
+        del build_arguments[i]
+    arguments.extend(build_arguments)
+    if opt_unity_mode != UnityMode.DEFAULT:
+        unity_disabled = DISABLE_UNITY_OPTION in build_arguments
+        if opt_unity_mode == UnityMode.ENABLE and unity_disabled:
+            arguments.remove(DISABLE_UNITY_OPTION)
+        elif opt_unity_mode == UnityMode.DISABLE and not unity_disabled:
+            arguments.append(DISABLE_UNITY_OPTION)
+    generator = read_config(GENERATOR_KEY)
+    if generator != 'Ninja':
+        arguments.extend(['--make-spec', 'ninja'])
+    jobs = read_int_config(JOBS_KEY)
+    if jobs > 1:
+        arguments.extend(['-j', str(jobs)])
+    if build_mode != BuildMode.BUILD:
+        arguments.append('--reuse-build')
+        if build_mode != BuildMode.RECONFIGURE:
+            arguments.append('--skip-cmake')
+    modules = read_config_modules_argument()
+    if modules:
+        arguments.append(modules)
+    if IS_WINDOWS and acceleration == Acceleration.INCREDIBUILD:
+        arg_string = ' '.join(arguments)
+        arguments = [INCREDIBUILD_CONSOLE, f'/command={arg_string}']
+
+    execute(arguments)
+
+    elapsed_time = int(time.time() - start_time)
+    print(f'--- Done({elapsed_time}s) ---')
+
+
+def build_base_docs():
+    arguments = [read_config_python_binary(), "setup.py", "build_base_docs", "--log-level",
+                 "quiet"]
+    for build_arg in read_config_build_arguments():
+        if build_arg.startswith("--qt-src-dir="):
+            arguments.append(build_arg)
+            break
+    execute(arguments)
+
+
+def run_tests():
+    """Run tests redirected into a log file with a time stamp"""
+    logfile_name = datetime.datetime.today().strftime("test_%Y%m%d_%H%M.txt")
+    binary = sys.executable
+    command = f'"{binary}" testrunner.py test > {logfile_name}'
+    print(command_log_string([command], Path.cwd()))
+    start_time = time.time()
+    result = 0 if opt_dry_run else os.system(command)
+    elapsed_time = int(time.time() - start_time)
+    print(f'--- Done({elapsed_time}s) ---')
+    return result
+
+
+def create_argument_parser(desc):
+    parser = ArgumentParser(description=desc, formatter_class=RawTextHelpFormatter)
+    parser.add_argument('--dry-run', '-d', action='store_true',
+                        help='Dry run, print commands')
+    parser.add_argument('--edit', '-e', action='store_true',
+                        help='Edit config file')
+    parser.add_argument('--reset', '-r', action='store_true',
+                        help='Git reset hard to upstream state')
+    parser.add_argument('--clean', '-c', action='store_true',
+                        help='Git clean')
+    parser.add_argument('--pull', '-p', action='store_true',
+                        help='Git pull')
+    parser.add_argument('--build', '-b', action='store_true',
+                        help='Build (configure + build)')
+    parser.add_argument('--make', '-m', action='store_true', help='Make')
+    parser.add_argument('--no-install', '-n', action='store_true',
+                        help='Run --build only, do not install')
+    parser.add_argument('--Make', '-M', action='store_true',
+                        help='cmake + Make (continue broken build)')
+    parser.add_argument('--test', '-t', action='store_true',
+                        help='Run tests')
+    parser.add_argument('--Documentation', '-D', action='store_true',
+                        help='Run build_base_docs')
+    parser.add_argument('--version', '-v', action='version', version='%(prog)s 1.0')
+    parser.add_argument('--verbose', '-V', action='store_true',
+                        help='Turn off --quiet specified in build arguments')
+    parser.add_argument('--unity', '-u', action='store_true',
+                        help='Force unity build')
+    parser.add_argument('--no-unity', action='store_true',
+                        help='Turn off --unity specified in build arguments')
+    return parser
+
+
+if __name__ == '__main__':
+    git = None
+    base_dir = None
+    config_file = None
+    user = None
+
+    config_file = get_config_file('qfp_tool.conf')
+    argument_parser = create_argument_parser(DESC.replace('%CONFIGFILE%', str(config_file)))
+    options = argument_parser.parse_args()
+    opt_dry_run = options.dry_run
+    opt_verbose = options.verbose
+
+    if options.unity:
+        opt_unity_mode = UnityMode.ENABLE
+    elif options.no_unity:
+        opt_unity_mode = UnityMode.DISABLE
+
+    if options.edit:
+        sys.exit(edit_config_file())
+
+    if options.build:
+        build_mode = BuildMode.BUILD
+    elif options.make:
+        build_mode = BuildMode.MAKE
+    elif options.Make:
+        build_mode = BuildMode.RECONFIGURE
+
+    if build_mode == BuildMode.NONE and not (options.clean or options.reset or options.pull
+                                             or options.Documentation or options.test):
+        argument_parser.print_help()
+        sys.exit(0)
+
+    git = 'git'
+    if which(git) is None:
+        warnings.warn('Unable to find git', RuntimeWarning)
+        sys.exit(-1)
+
+    if not config_file.exists():
+        print('Create initial config file ', config_file, " ..")
+        with open(config_file, 'w') as f:
+            f.write(DEFAULT_CONFIG_FILE.format(' '.join(DEFAULT_BUILD_ARGS)))
+
+    while not Path(".git").exists():
+        cwd = Path.cwd()
+        cwd_s = os.fspath(cwd)
+        if cwd_s == '/' or (IS_WINDOWS and len(cwd_s) < 4):
+            warnings.warn('Unable to find git root', RuntimeWarning)
+            sys.exit(-1)
+        os.chdir(cwd.parent)
+
+    base_dir = Path.cwd().name
+
+    if options.clean:
+        run_git(['clean', '-dxf'])
+
+    if options.reset:
+        run_git(['reset', '--hard', '@{upstream}'])
+
+    if options.pull:
+        run_git(['pull', '--rebase'])
+
+    if build_mode != BuildMode.NONE:
+        target = 'build' if options.no_install else 'install'
+        build(target)
+
+    if options.Documentation:
+        build_base_docs()
+
+    if options.test:
+        sys.exit(run_tests())
+
+    sys.exit(0)
diff --git a/build_scripts/qp5_tool.py b/build_scripts/qp5_tool.py
deleted file mode 100644 (file)
index 4ec0d63..0000000
+++ /dev/null
@@ -1,416 +0,0 @@
-# Copyright (C) 2019 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-import datetime
-import os
-import re
-import subprocess
-import sys
-import time
-import warnings
-from argparse import ArgumentParser, RawTextHelpFormatter
-from enum import Enum
-from pathlib import Path
-from typing import List
-
-DESC = """
-Utility script for working with Qt for Python.
-
-Feel free to extend!
-
-Typical Usage:
-Update and build a repository: python qp5_tool -p -b
-
-qp5_tool.py uses a configuration file "%CONFIGFILE%"
-in the format key=value.
-
-It is possible to use repository-specific values by adding a key postfixed by
-a dash and the repository folder base name, eg:
-Modules-pyside-setup512=Core,Gui,Widgets,Network,Test
-
-Configuration keys:
-Acceleration     Incredibuild or unset
-BuildArguments   Arguments to setup.py
-Generator        Generator to be used for CMake. Currently, only Ninja is
-                 supported.
-Jobs             Number of jobs to be run simultaneously
-Modules          Comma separated list of modules to be built
-                 (for --module-subset=)
-Python           Python executable (Use python_d for debug builds on Windows)
-
-Arbitrary keys can be defined and referenced by $(name):
-
-MinimalModules=Core,Gui,Widgets,Network,Test
-Modules=$(MinimalModules),Multimedia
-Modules-pyside-setup-minimal=$(MinimalModules)
-"""
-
-
-class Acceleration(Enum):
-    NONE = 0
-    INCREDIBUILD = 1
-
-
-class BuildMode(Enum):
-    NONE = 0
-    BUILD = 1
-    RECONFIGURE = 2
-    MAKE = 3
-
-
-DEFAULT_BUILD_ARGS = ['--build-tests', '--skip-docs', '--quiet']
-IS_WINDOWS = sys.platform == 'win32'
-INCREDIBUILD_CONSOLE = 'BuildConsole' if IS_WINDOWS else '/opt/incredibuild/bin/ib_console'
-# Config file keys
-ACCELERATION_KEY = 'Acceleration'
-BUILDARGUMENTS_KEY = 'BuildArguments'
-GENERATOR_KEY = 'Generator'
-JOBS_KEY = 'Jobs'
-MODULES_KEY = 'Modules'
-PYTHON_KEY = 'Python'
-
-DEFAULT_MODULES = "Core,Gui,Widgets,Network,Test,Qml,Quick,Multimedia,MultimediaWidgets"
-DEFAULT_CONFIG_FILE = f"Modules={DEFAULT_MODULES}\n"
-
-build_mode = BuildMode.NONE
-opt_dry_run = False
-opt_verbose = False
-
-
-def which(needle: str):
-    """Perform a path search"""
-    needles = [needle]
-    if IS_WINDOWS:
-        for ext in ("exe", "bat", "cmd"):
-            needles.append(f"{needle}.{ext}")
-
-    for path in os.environ.get("PATH", "").split(os.pathsep):
-        for n in needles:
-            binary = Path(path) / n
-            if binary.is_file():
-                return binary
-    return None
-
-
-def command_log_string(args: List[str], directory: Path):
-    result = f'[{directory.name}]'
-    for arg in args:
-        result += f' "{arg}"' if ' ' in arg else f' {arg}'
-    return result
-
-
-def execute(args: List[str]):
-    """Execute a command and print to log"""
-    log_string = command_log_string(args, Path.cwd())
-    print(log_string)
-    if opt_dry_run:
-        return
-    exit_code = subprocess.call(args)
-    if exit_code != 0:
-        raise RuntimeError(f'FAIL({exit_code}): {log_string}')
-
-
-def run_process_output(args):
-    """Run a process and return its output. Also run in dry_run mode"""
-    std_out = subprocess.Popen(args, universal_newlines=1,
-                               stdout=subprocess.PIPE).stdout
-    result = [line.rstrip() for line in std_out.readlines()]
-    std_out.close()
-    return result
-
-
-def run_git(args):
-    """Run git in the current directory and its submodules"""
-    args.insert(0, git)  # run in repo
-    execute(args)  # run for submodules
-
-
-def expand_reference(cache_dict, value):
-    """Expand references to other keys in config files $(name) by value."""
-    pattern = re.compile(r"\$\([^)]+\)")
-    while True:
-        match = pattern.match(value)
-        if not match:
-            break
-        key = match.group(0)[2:-1]
-        value = value[:match.start(0)] + cache_dict[key] + value[match.end(0):]
-    return value
-
-
-def editor():
-    editor = os.getenv('EDITOR')
-    if not editor:
-        return 'notepad' if IS_WINDOWS else 'vi'
-    editor = editor.strip()
-    if IS_WINDOWS:
-        # Windows: git requires quotes in the variable
-        if editor.startswith('"') and editor.endswith('"'):
-            editor = editor[1:-1]
-        editor = editor.replace('/', '\\')
-    return editor
-
-
-def edit_config_file():
-    exit_code = -1
-    try:
-        exit_code = subprocess.call([editor(), config_file])
-    except Exception as e:
-        reason = str(e)
-        print(f'Unable to launch: {editor()}: {reason}')
-    return exit_code
-
-
-"""
-Config file handling, cache and read function
-"""
-config_dict = {}
-
-
-def read_config_file(file_name):
-    """Read the config file into config_dict, expanding continuation lines"""
-    global config_dict
-    keyPattern = re.compile(r'^\s*([A-Za-z0-9\_\-]+)\s*=\s*(.*)$')
-    with open(file_name) as f:
-        while True:
-            line = f.readline()
-            if not line:
-                break
-            line = line.rstrip()
-            match = keyPattern.match(line)
-            if match:
-                key = match.group(1)
-                value = match.group(2)
-                while value.endswith('\\'):
-                    value = value.rstrip('\\')
-                    value += f.readline().rstrip()
-                config_dict[key] = expand_reference(config_dict, value)
-
-
-def read_config(key):
-    """
-    Read a value from the '$HOME/.qp5_tool' configuration file. When given
-    a key 'key' for the repository directory '/foo/qt-5', check for the
-    repo-specific value 'key-qt5' and then for the general 'key'.
-    """
-    if not config_dict:
-        read_config_file(config_file)
-    repo_value = config_dict.get(f"{key}-{base_dir}")
-    return repo_value if repo_value else config_dict.get(key)
-
-
-def read_bool_config(key):
-    value = read_config(key)
-    return value and value in ['1', 'true', 'True']
-
-
-def read_int_config(key, default=-1):
-    value = read_config(key)
-    return int(value) if value else default
-
-
-def read_acceleration_config():
-    value = read_config(ACCELERATION_KEY)
-    if value:
-        value = value.lower()
-        if value == 'incredibuild':
-            return Acceleration.INCREDIBUILD
-    return Acceleration.NONE
-
-
-def read_config_build_arguments():
-    value = read_config(BUILDARGUMENTS_KEY)
-    if value:
-        return re.split(r'\s+', value)
-    return DEFAULT_BUILD_ARGS
-
-
-def read_config_modules_argument():
-    value = read_config(MODULES_KEY)
-    if value and value != '' and value != 'all':
-        return f"--module-subset={value}"
-    return None
-
-
-def read_config_python_binary() -> str:
-    binary = read_config(PYTHON_KEY)
-    virtual_env = os.environ.get('VIRTUAL_ENV')
-    if not binary:
-        # Use 'python3' unless virtualenv is set
-        use_py3 = not virtual_env and which('python3')
-        binary = 'python3' if use_py3 else 'python'
-    binary = Path(binary)
-    if not binary.is_absolute():
-        abs_path = which(str(binary))
-        if abs_path:
-            binary = abs_path
-        else:
-            warnings.warn(f'Unable to find "{binary}"', RuntimeWarning)
-    if virtual_env:
-        if not str(binary).startswith(virtual_env):
-            w = f'Python "{binary}" is not under VIRTUAL_ENV "{virtual_env}"'
-            warnings.warn(w, RuntimeWarning)
-    return str(binary)
-
-
-def get_config_file(base_name) -> Path:
-    global user
-    home = os.getenv('HOME')
-    if IS_WINDOWS:
-        # Set a HOME variable on Windows such that scp. etc.
-        # feel at home (locating .ssh).
-        if not home:
-            home = os.getenv('HOMEDRIVE') + os.getenv('HOMEPATH')
-            os.environ['HOME'] = home
-        user = os.getenv('USERNAME')
-        config_file = Path(os.getenv('APPDATA')) / base_name
-    else:
-        user = os.getenv('USER')
-        config_dir = Path(home) / '.config'
-        if config_dir.exists():
-            config_file = config_dir / base_name
-        else:
-            config_file = Path(home) / f".{base_name}"
-    return config_file
-
-
-def build(target: str):
-    """Run configure and build steps"""
-    start_time = time.time()
-
-    arguments = []
-    acceleration = read_acceleration_config()
-    if not IS_WINDOWS and acceleration == Acceleration.INCREDIBUILD:
-        arguments.append(INCREDIBUILD_CONSOLE)
-        arguments.appendh('--avoid')  # caching, v0.96.74
-    arguments.extend([read_config_python_binary(), 'setup.py', target])
-    build_arguments = read_config_build_arguments()
-    if opt_verbose and '--quiet' in build_arguments:
-        build_arguments.remove('--quiet')
-    arguments.extend(build_arguments)
-    generator = read_config(GENERATOR_KEY)
-    if generator != 'Ninja':
-        arguments.extend(['--make-spec', 'ninja'])
-    jobs = read_int_config(JOBS_KEY)
-    if jobs > 1:
-        arguments.extend(['-j', str(jobs)])
-    if build_mode != BuildMode.BUILD:
-        arguments.extend(['--reuse-build', '--ignore-git'])
-        if build_mode != BuildMode.RECONFIGURE:
-            arguments.append('--skip-cmake')
-    modules = read_config_modules_argument()
-    if modules:
-        arguments.append(modules)
-    if IS_WINDOWS and acceleration == Acceleration.INCREDIBUILD:
-        arg_string = ' '.join(arguments)
-        arguments = [INCREDIBUILD_CONSOLE, f'/command={arg_string}']
-
-    execute(arguments)
-
-    elapsed_time = int(time.time() - start_time)
-    print(f'--- Done({elapsed_time}s) ---')
-
-
-def run_tests():
-    """Run tests redirected into a log file with a time stamp"""
-    logfile_name = datetime.datetime.today().strftime("test_%Y%m%d_%H%M.txt")
-    binary = sys.executable
-    command = f'"{binary}" testrunner.py test > {logfile_name}'
-    print(command_log_string([command], Path.cwd()))
-    start_time = time.time()
-    result = 0 if opt_dry_run else os.system(command)
-    elapsed_time = int(time.time() - start_time)
-    print(f'--- Done({elapsed_time}s) ---')
-    return result
-
-
-def create_argument_parser(desc):
-    parser = ArgumentParser(description=desc, formatter_class=RawTextHelpFormatter)
-    parser.add_argument('--dry-run', '-d', action='store_true',
-                        help='Dry run, print commands')
-    parser.add_argument('--edit', '-e', action='store_true',
-                        help='Edit config file')
-    parser.add_argument('--reset', '-r', action='store_true',
-                        help='Git reset hard to upstream state')
-    parser.add_argument('--clean', '-c', action='store_true',
-                        help='Git clean')
-    parser.add_argument('--pull', '-p', action='store_true',
-                        help='Git pull')
-    parser.add_argument('--build', '-b', action='store_true',
-                        help='Build (configure + build)')
-    parser.add_argument('--make', '-m', action='store_true', help='Make')
-    parser.add_argument('--no-install', '-n', action='store_true',
-                        help='Run --build only, do not install')
-    parser.add_argument('--Make', '-M', action='store_true',
-                        help='cmake + Make (continue broken build)')
-    parser.add_argument('--test', '-t', action='store_true',
-                        help='Run tests')
-    parser.add_argument('--version', '-v', action='version', version='%(prog)s 1.0')
-    parser.add_argument('--verbose', '-V', action='store_true',
-                        help='Turn off --quiet specified in build arguments')
-    return parser
-
-
-if __name__ == '__main__':
-    git = None
-    base_dir = None
-    config_file = None
-    user = None
-
-    config_file = get_config_file('qp5_tool.conf')
-    argument_parser = create_argument_parser(DESC.replace('%CONFIGFILE%', str(config_file)))
-    options = argument_parser.parse_args()
-    opt_dry_run = options.dry_run
-    opt_verbose = options.verbose
-
-    if options.edit:
-        sys.exit(edit_config_file())
-
-    if options.build:
-        build_mode = BuildMode.BUILD
-    elif options.make:
-        build_mode = BuildMode.MAKE
-    elif options.Make:
-        build_mode = BuildMode.RECONFIGURE
-
-    if build_mode == BuildMode.NONE and not (options.clean or options.reset
-                                             or options.pull or options.test):
-        argument_parser.print_help()
-        sys.exit(0)
-
-    git = 'git'
-    if which(git) is None:
-        warnings.warn('Unable to find git', RuntimeWarning)
-        sys.exit(-1)
-
-    if not config_file.exists():
-        print('Create initial config file ', config_file, " ..")
-        with open(config_file, 'w') as f:
-            f.write(DEFAULT_CONFIG_FILE.format(' '.join(DEFAULT_BUILD_ARGS)))
-
-    while not Path(".git").exists():
-        cwd = Path.cwd()
-        cwd_s = os.fspath(cwd)
-        if cwd_s == '/' or (IS_WINDOWS and len(cwd_s) < 4):
-            warnings.warn('Unable to find git root', RuntimeWarning)
-            sys.exit(-1)
-        os.chdir(cwd.parent)
-
-    base_dir = Path.cwd().name
-
-    if options.clean:
-        run_git(['clean', '-dxf'])
-
-    if options.reset:
-        run_git(['reset', '--hard', '@{upstream}'])
-
-    if options.pull:
-        run_git(['pull', '--rebase'])
-
-    if build_mode != BuildMode.NONE:
-        target = 'build' if options.no_install else 'install'
-        build(target)
-
-    if options.test:
-        sys.exit(run_tests())
-
-    sys.exit(0)
index 6a7de04c9f4ee09bc1a86f142a8ba1e12083a100..9bcbb4afe271ca28905522850f1b9b10012d4ca3 100644 (file)
@@ -93,7 +93,7 @@ class SetupRunner(object):
                 setup_cmd.append(self.construct_cmd_line_argument(name, value))
 
         # Add --reuse-build option if requested and not already present.
-        if (reuse_build and command in ('bdist_wheel', 'build', 'build_rst_docs', 'install')
+        if (reuse_build and command in ('bdist_wheel', 'build', 'build_base_docs', 'build_rst_docs', 'install')
                 and not self.cmd_line_argument_is_in_args("reuse-build", modified_argv)):
             setup_cmd.append(self.construct_cmd_line_argument("reuse-build"))
         return setup_cmd
index 1ee3e39aaa079457019ac77de01b73918d627821..74d9e6fc5ac19718b13a9f9965e27c59e38725ef 100644 (file)
@@ -20,7 +20,6 @@ from .log import log
 from . import (PYSIDE_PYTHON_TOOLS, PYSIDE_LINUX_BIN_TOOLS, PYSIDE_UNIX_LIBEXEC_TOOLS,
                PYSIDE_WINDOWS_BIN_TOOLS, PYSIDE_UNIX_BIN_TOOLS, PYSIDE_UNIX_BUNDLED_TOOLS)
 
-from setuptools.errors import SetupError
 
 try:
     WindowsError
@@ -95,8 +94,8 @@ def copyfile(src, dst, force=True, _vars=None, force_copy_symlink=False,
         src = Path(src.format(**_vars)) if _vars else Path(src)
     if isinstance(dst, str):
         dst = Path(dst.format(**_vars)) if _vars else Path(dst)
-    assert(isinstance(src, Path))
-    assert(isinstance(dst, Path))
+    assert (isinstance(src, Path))
+    assert (isinstance(dst, Path))
 
     if not src.exists() and not force:
         log.info(f"**Skipping copy file\n  {src} to\n  {dst}\n  Source does not exist")
@@ -171,8 +170,8 @@ def copydir(src, dst, _filter=None, ignore=None, force=True, recursive=True, _va
         src = Path(src.format(**_vars)) if _vars else Path(src)
     if isinstance(dst, str):
         dst = Path(dst.format(**_vars)) if _vars else Path(dst)
-    assert(isinstance(src, Path))
-    assert(isinstance(dst, Path))
+    assert (isinstance(src, Path))
+    assert (isinstance(dst, Path))
 
     if _vars is not None:
         if _filter is not None:
@@ -950,7 +949,7 @@ def get_qtci_virtualEnv(python_ver, host, hostArch, targetArch):
                 _path = Path(os.getenv(var, ""))
                 _pExe = _path / "python.exe"
                 if not _pExe.is_file():
-                    log.warn(f"Can't find python.exe from {_pExe}, using default python3")
+                    log.warning(f"Can't find python.exe from {_pExe}, using default python3")
                     _pExe = Path(os.getenv("PYTHON3_32_PATH")) / "python.exe"
             else:
                 _pExe = Path(os.getenv("PYTHON2_32_PATH")) / "python.exe"
@@ -961,7 +960,7 @@ def get_qtci_virtualEnv(python_ver, host, hostArch, targetArch):
                 _path = Path(os.getenv(var, ""))
                 _pExe = _path / "python.exe"
                 if not _pExe.is_file():
-                    log.warn(f"Can't find python.exe from {_pExe}, using default python3")
+                    log.warning(f"Can't find python.exe from {_pExe}, using default python3")
                     _pExe = Path(os.getenv("PYTHON3_PATH")) / "python.exe"
         env_python = f"{_env}\\Scripts\\python.exe"
         env_pip = f"{_env}\\Scripts\\pip.exe"
@@ -972,7 +971,7 @@ def get_qtci_virtualEnv(python_ver, host, hostArch, targetArch):
         except Exception as e:
             print(f"Exception {type(e).__name__}: {e}")
             _pExe = "python3"
-    return(_pExe, _env, env_pip, env_python)
+    return (_pExe, _env, env_pip, env_python)
 
 
 def run_instruction(instruction, error, initial_env=None):
@@ -1135,7 +1134,7 @@ def available_pyside_tools(qt_tools_path: Path, package_for_wheels: bool = False
                              if tool_exist(bin_path / f"{tool}.exe")])
     else:
         lib_exec_path = qt_tools_path / "Qt" / "libexec" if package_for_wheels \
-                        else qt_tools_path / "libexec"
+            else qt_tools_path / "libexec"
         pyside_tools.extend([tool for tool in PYSIDE_UNIX_LIBEXEC_TOOLS
                              if tool_exist(lib_exec_path / tool)])
         if sys.platform == 'darwin':
index ec66b957f51051e05053ccc22eae9913b33fc673..2112bba9af35c2be5ef2ac5b7d91dc3762975a41 100644 (file)
@@ -166,6 +166,7 @@ def wheel_files_pyside_essentials() -> List[ModuleData]:
         module_QtQml(),
         module_QtQuick(),
         module_QtQuickControls2(),
+        module_QtQuickTest(),
         module_QtQuickWidgets(),
         module_QtXml(),
         module_QtTest(),
@@ -458,6 +459,7 @@ def module_QtQml() -> ModuleData:
         "libQt6QmlCore",
         "libQt6QmlLocalStorage",
         "libQt6QmlModels",
+        "libQt6QmlNetwork",
         "libQt6QmlWorkerScript",
         "libQt6QmlXmlListModel",
         "libQt6QmlCompiler"
@@ -559,6 +561,7 @@ def module_QtQuick() -> ModuleData:
         "libQt6QuickTemplates2",
         "libQt6QuickTest",
         "libQt6QuickTimeline",
+        "libQt6QuickTimelineBlendTrees",
     ]
 
     # Adding GraphicalEffects files
@@ -574,12 +577,35 @@ def module_QtQuick() -> ModuleData:
 
 def module_QtQuickControls2() -> ModuleData:
     data = ModuleData("QuickControls2")
+    data.qtlib.append("libQt6QuickControls2")
+    data.qtlib.append("libQt6QuickControls2Basic")
+    data.qtlib.append("libQt6QuickControls2BasicStyleImpl")
+    data.qtlib.append("libQt6QuickControls2Fusion")
+    data.qtlib.append("libQt6QuickControls2FusionStyleImpl")
+    data.qtlib.append("libQt6QuickControls2Imagine")
+    data.qtlib.append("libQt6QuickControls2ImagineStyleImpl")
     data.qtlib.append("libQt6QuickControls2Impl")
+    data.qtlib.append("libQt6QuickControls2Material")
+    data.qtlib.append("libQt6QuickControls2MaterialStyleImpl")
+    data.qtlib.append("libQt6QuickControls2Universal")
+    data.qtlib.append("libQt6QuickControls2UniversalStyleImpl")
+    if sys.platform == "win32":
+        data.qtlib.append("libQt6QuickControls2WindowsStyleImpl")
+    elif sys.platform == "darwin":
+        data.qtlib.append("libQt6QuickControls2IOSStyleImpl")
+        data.qtlib.append("libQt6QuickControls2MacOSStyleImpl")
+
     data.metatypes.append("qt6quickcontrols2impl_relwithdebinfo_metatypes.json")
 
     return data
 
 
+def module_QtQuickTest() -> ModuleData:
+    data = ModuleData("QuickTest")
+
+    return data
+
+
 def module_QtQuickWidgets() -> ModuleData:
     data = ModuleData("QuickWidgets")
     return data
@@ -704,10 +730,14 @@ def module_QtQuick3D() -> ModuleData:
         "libQt6Quick3DEffects",
         "libQt6Quick3DGlslParser",
         "libQt6Quick3DHelpers",
+        "libQt6Quick3DHelpersImpl",
         "libQt6Quick3DIblBaker",
         "libQt6Quick3DParticleEffects",
         "libQt6Quick3DParticles",
+        "libQt6Quick3DPhysics",
+        "libQt6Quick3DPhysicsHelpers",
         "libQt6Quick3DRuntimeRender",
+        "libQt6Quick3DSpatialAudio",
         "libQt6Quick3DUtils",
         "libQt6ShaderTools",
         "libQt63DQuick",
@@ -744,6 +774,8 @@ def module_QtQuick3D() -> ModuleData:
     data.qtlib.extend(_qtlib)
     data.metatypes.extend(_metatypes)
     data.extra_files.append("Qt/plugins/assetimporters/libassimp*")
+    data.extra_files.append("qsb*")
+    data.extra_files.append("balsam*")
 
     return data
 
@@ -818,6 +850,10 @@ def module_QtMultimedia() -> ModuleData:
     data.translations.append("qtmultimedia_*")
     data.plugins = get_module_plugins(json_data)
 
+    if sys.platform == "win32":
+        data.extra_files.extend(["avcodec-60.dll", "avformat-60.dll", "avutil-58.dll",
+                                 "swresample-4.dll", "swscale-7.dll"])
+
     return data
 
 
@@ -961,6 +997,8 @@ def module_QtSerialBus() -> ModuleData:
 def module_QtVirtualKeyboard() -> ModuleData:
     data = ModuleData("VirtualKeyboard")
     data.plugins.append("virtualkeyboard")
+    data.qtlib.append("libQt6VirtualKeyboardSettings")
+
     return data
 
 
index 2bf2feb276b00834c4c3ede48dafbe348d0bbce2..c03b1b8ae002a0448874f1d27a83cfe0538fb460 100644 (file)
@@ -1,6 +1,6 @@
 product_dependency:
   ../../qt/qt5:
-    ref: "15b7e7434fd79334a5cf071e36cee7663fe1fb45"
+    ref: "3f005f1e2e88485dbf541200ba3fafcad6ea84ad"
 dependency_source: supermodule
 dependencies: [
       "../../qt/qt3d",
index 8cb3c1d5086dcc0e73926f8b0355f1d7f0adb465..441a018032116622444bb42eb65302c1db67b8a4 100644 (file)
@@ -34,6 +34,18 @@ instructions:
           - condition: property
             property: host.os
             equals_value: Windows
+    - type: EnvironmentVariable
+      variableName: PYTHON3_PATH
+      variableValue: "{{ index .Env \"PYTHON3.10.0-64_PATH\"}}"
+      enable_if:
+        condition: and
+        conditions:
+          - condition: property
+            property: host.osVersion
+            equals_value: Windows_11_22H2
+          - condition: property
+            property: host.os
+            equals_value: Windows
     - type: EnvironmentVariable
       variableName: TARGET_ARCHITECTURE
       variableValue: amd64_x86
@@ -118,7 +130,7 @@ instructions:
          equals_value: MacOS
     - type: PrependToEnvironmentVariable
       variableName: PATH
-      variableValue: "{{.Env.PYTHON3_PATH}};"
+      variableValue: "{{ index .Env \"PYTHON3.10.0-64_PATH\"}};"
       enable_if:
          condition: property
          property: host.os
@@ -191,21 +203,6 @@ instructions:
           - condition: property
             property: host.os
             equals_value: MacOS
-    - type: ExecuteCommand
-      command: "keyring --disable"
-      maxTimeInSeconds: 14400
-      maxTimeBetweenOutput: 1200
-      enable_if:
-          condition: and
-          conditions:
-            - condition: property
-              property: host.os
-              equals_value: Linux
-            - condition: property
-              property: host.arch
-              equals_value: AARCH64
-      userMessageOnFailure: >
-          Failed to disable keyring
     - type: ExecuteCommand
       command: "sudo apt-get install python3-pip libclang-11-dev clang -y"
       maxTimeInSeconds: 14400
@@ -222,7 +219,7 @@ instructions:
       userMessageOnFailure: >
           Failed to install dependencies
     - type: ExecuteCommand
-      command: "python3 -m pip install -U setuptools==67.7.2"
+      command: "python3 -m pip install -U setuptools==69.1.1"
       maxTimeInSeconds: 14400
       maxTimeBetweenOutput: 1200
       enable_if:
index 4b8fb41c9e92bdf269287a16da0ff26eb147601e..317adae2a1eb7879d2c4a5dfd5e01a2ef65079ec 100644 (file)
@@ -1,7 +1,7 @@
 type: Group
 instructions:
   - type: ExecuteCommand
-    command: "python3 -m pip install -U setuptools==67.7.2"
+    command: "python3 -m pip install -U setuptools==69.1.1"
     maxTimeInSeconds: 14400
     maxTimeBetweenOutput: 1200
     enable_if:
@@ -40,22 +40,15 @@ instructions:
           equals_value: MacOS
     userMessageOnFailure: >
          Failed to execute build instructions on macOS
-  - type: EnvironmentVariable
-    variableName: PYSIDE_SIGNING_DIR
-    variableValue: "{{.AgentWorkingDir}}\\pyside\\{{.Env.TESTED_MODULE_COIN}}\\build\\qfpa-p3.8\\package_for_wheels"
-    enable_if:
-        condition: property
-        property: host.osVersion
-        contains_value: "Windows_11"
   - type: EnvironmentVariable
     variableName: PYSIDE_SIGNING_DIR
     variableValue: "{{.AgentWorkingDir}}\\pyside\\{{.Env.TESTED_MODULE_COIN}}\\build\\qfpa-p3.10\\package_for_wheels"
     enable_if:
         condition: property
-        property: host.osVersion
-        contains_value: "Windows_10"
+        property: host.os
+        equals_value: Windows
   - type: ExecuteCommand
-    command: "{{.Env.interpreter}} -m pip install -U pip setuptools==67.7.2 --user"
+    command: "{{.Env.interpreter}} -m pip install -U pip setuptools==69.1.1 --user"
     maxTimeInSeconds: 14400
     maxTimeBetweenOutput: 1200
     enable_if:
@@ -75,7 +68,7 @@ instructions:
     userMessageOnFailure: >
          Failed to execute build instructions on Linux
   - type: ExecuteCommand
-    command: "c:\\users\\qt\\MSVC.bat {{.Env.PYTHON3_PATH}}\\python.exe -m pip install -U setuptools==67.7.2"
+    command: "c:\\users\\qt\\MSVC.bat {{.Env.PYTHON3_PATH}}\\python.exe -m pip install -U setuptools==69.1.1"
     maxTimeInSeconds: 14400
     maxTimeBetweenOutput: 1200
     enable_if:
index 23e975ce1fe512d84bbfc15dee1b6968331480e1..780b27ec7ddb821205bafc5baf4d2e95548d3dff 100644 (file)
@@ -5,7 +5,7 @@ enable_if:
   not_contains_value: LicenseCheck
 instructions:
   - type: ExecuteCommand
-    command: "python3 -m pip install -U setuptools==67.7.2"
+    command: "python3 -m pip install -U setuptools==69.1.1"
     maxTimeInSeconds: 14400
     maxTimeBetweenOutput: 1200
     enable_if:
@@ -45,7 +45,7 @@ instructions:
     userMessageOnFailure: >
          Failed to execute test instructions on macOS
   - type: ExecuteCommand
-    command: "{{.Env.interpreter}} -m pip install -U pip setuptools==67.7.2 --user"
+    command: "{{.Env.interpreter}} -m pip install -U pip setuptools==69.1.1 --user"
     maxTimeInSeconds: 14400
     maxTimeBetweenOutput: 1200
     enable_if:
@@ -65,7 +65,7 @@ instructions:
     userMessageOnFailure: >
          Failed to execute test instructions on Linux
   - type: ExecuteCommand
-    command: "c:\\users\\qt\\MSVC.bat {{.Env.PYTHON3_PATH}}\\python.exe -m pip install -U pip setuptools==67.7.2 --user"
+    command: "c:\\users\\qt\\MSVC.bat {{.Env.PYTHON3_PATH}}\\python.exe -m pip install -U pip setuptools==69.1.1 --user"
     maxTimeInSeconds: 14400
     maxTimeBetweenOutput: 1200
     enable_if:
index 8f9bed82fd41086c7b5a9598fb802d3d763c0d13..015a86eab1e6437345b9dc879f051b3d348b9f11 100644 (file)
@@ -18,6 +18,13 @@ instructions:
       condition: property
       property: host.compiler
       equals_value: MSVC2019
+  - type: EnvironmentVariable
+    variableName: VC_SCRIPT
+    variableValue: "\\Program Files\\Microsoft Visual Studio\\2022\\Professional\\VC\\Auxiliary\\Build\\vcvarsall.bat"
+    enable_if:
+      condition: property
+      property: host.compiler
+      equals_value: MSVC2022
   - type: WriteFile
     fileContents: "call \"{{.Env.VC_SCRIPT}}\" {{.Env.TARGET_ARCHITECTURE}} \r\ncmd /c %*"
     filename: "c:\\users\\qt\\MSVC.bat"
index 03f865bdbb80779e71443059e9039329085f9a28..e5c2fdc8c578ee12f3bcf2662a575e2692e56691 100644 (file)
@@ -18,50 +18,69 @@ accept_configuration:
           not_contains_value: UseLegacyInstructions
         - condition: property  # MinGW and msvc2015 are not supported
           property: target.compiler
-          not_in_values: [Mingw, MSVC2015]
+          not_in_values: [Mingw, MSVC2015,Clang]
         - condition: property  # Webassembly
           property: target.osVersion
           not_equals_value: WebAssembly
         - condition: property  # Windows on Arm
           property: target.arch
           not_equals_value: ARM64
+        - condition: property  # Windows on Arm host build
+          property: target.arch
+          not_equals_value: AARCH64
         - condition: property
           property: features
           not_contains_value: DebianPackaging
+        - condition: property
+          property: target.osVersion
+          not_equals_value: VxWorks
     - condition: and
       conditions:
-        - condition: property  # No cross compilation
-          property: host.osVersion
-          equals_value: MacOS_10_15
+        - condition: property
+          property: host.os
+          equals_value: MacOS
         - condition: property
           property: features
           contains_value: TestOnly
         - condition: property
           property: features
           contains_value: Packaging
+        - condition: property
+          property: target.os
+          not_contains_value: Android
+        - condition: property
+          property: target.os
+          not_contains_value: IOS
     - condition: and
       conditions:
         - condition: property
           property: host.osVersion
           equals_value: MacOS_11_00
+        - condition: property
+          property: host.arch
+          equals_value: ARM64
+        - condition: property
+          property: features
+          contains_value: TestOnly
         - condition: property
           property: features
           contains_value: Packaging
-    - condition: and
+    - condition: and # Restore LoA config
       conditions:
         - condition: property
           property: host.osVersion
-          equals_value: MacOS_11_00
+          equals_value: Debian_11_6
         - condition: property
           property: host.arch
-          equals_value: ARM64
+          equals_value: AARCH64
         - condition: property
           property: features
-          contains_value: TestOnly
+          not_contains_value: DebianPackaging
         - condition: property
           property: features
           contains_value: Packaging
 
+
 machine_type:
   Build:
     cores: 8
index 0f278dbcf40b3abe0447c2d069b7ba192be77507..83d46977ee64133bcf4eabc287029623d17bacd3 100644 (file)
@@ -157,10 +157,7 @@ if __name__ == "__main__":
         python_ver = "3.11"
     wheel_package_dir = "qfpa-p3.6"
     if CI_TARGET_OS in ["Windows"]:
-        if (os.environ.get("HOST_OSVERSION_COIN")).startswith("windows_10"):
-            python_ver = "3.10.0"
-        else:
-            python_ver = "3.8.1"
+        python_ver = "3.10.0"
     if CI_TEST_PHASE in ["ALL", "BUILD"]:
         call_setup(python_ver, "BUILD")
     # Until CI has a feature to set more dynamic signing dir, make sure it actually exist
index 219fcf377e94155e4056fa51231f32e1dc5b6f59..b0e71fba7c8a6030cbbe11abf7957d903c66d975 100644 (file)
@@ -96,10 +96,7 @@ def run_test_instructions():
 
     # In win machines, there are additional python versions to test with
     if CI_HOST_OS == "Windows":
-        if (os.environ.get('HOST_OSVERSION_COIN')).startswith('windows_10'):
-            call_testrunner("3.10.0", str(testRun))
-        else:
-            call_testrunner("3.8.1", str(testRun))
+        call_testrunner("3.10.0", str(testRun))
     elif CI_HOST_OS == "Linux":
         call_testrunner("3.11", str(testRun))
     else:
index 1b34fa402fe7f1b508c6d37073ee362e7997a522..063b59c450eb079dbe470fcf6bdc1b47cc01133e 100644 (file)
@@ -5,6 +5,7 @@ import os
 import platform
 import sys
 import importlib
+import json
 from argparse import ArgumentParser, Namespace
 from dataclasses import dataclass
 from pathlib import Path
@@ -45,7 +46,21 @@ def get_version_from_package(name: str, package_path: Path) -> str:
     return version, f"{name}.__init__.__version__"
 
 
-def get_manifest(wheel_name: str, data: List[ModuleData]) -> str:
+def create_module_plugin_json(wheel_name: str, data: List[ModuleData], package_path: Path):
+    all_plugins = {}
+
+    for module in data:
+        all_plugins[module.name] = getattr(module, "plugins")
+
+    # write the dictionary modules->plugins dictionary to a .json file and include this .json file
+    # This file is picked up by the deployment tool to figure out the plugin dependencies
+    # of a PySide6 application
+    if all_plugins:
+        with open(f"{package_path}/PySide6/{wheel_name}.json", 'w') as fp:
+            json.dump(all_plugins, fp, indent=4)
+
+
+def get_manifest(wheel_name: str, data: List[ModuleData], package_path: Path) -> str:
     lines = []
 
     for module in data:
@@ -74,6 +89,9 @@ def get_manifest(wheel_name: str, data: List[ModuleData]) -> str:
     lines.append("recursive-exclude PySide6/Qt/qml *.debug")
     lines.append("prune PySide6/Qt/qml/QtQuick3D/MaterialEditor")
 
+    # adding PySide6_Essentials.json and PySide6_Addons.json
+    lines.append(f"include PySide6/{wheel_name}.json")
+
     return "\n".join(lines)
 
 
@@ -441,7 +459,13 @@ if __name__ == "__main__":
         with open(pyproject_toml_path, "w") as f:
             f.write(pyproject_toml_content)
 
-        # 3. Create the 'MANIFEST.in'
+        # 3. Create PySide_Essentials.json and PySide_Addons.json
+        # creates a json file mapping each Qt module to the possible plugin dependencies
+        if data is not None:
+            print(f"-- Creating {name}.json")
+            create_module_plugin_json(name, data, package_path)
+
+        # 4. Create the 'MANIFEST.in'
         # Special case for shiboken and shiboken_generator
         # so we copy the whole directory, only PySide and derivatives
         # will need to have specific information
@@ -449,7 +473,7 @@ if __name__ == "__main__":
         if data is None:
             manifest_content = get_simple_manifest(name)
         else:
-            manifest_content = get_manifest(name, data)
+            manifest_content = get_manifest(name, data, package_path)
         with open(package_path / "MANIFEST.in", "w") as f:
             f.write(manifest_content)
 
@@ -461,7 +485,7 @@ if __name__ == "__main__":
         for fname in _files:
             copy(fname, package_path)
 
-        # 5. call the build module to create the wheel
+        # 6. call the build module to create the wheel
         print("-- Creating wheels")
         if not verbose:
             _runner = pyproject_hooks.quiet_subprocess_runner
@@ -470,7 +494,7 @@ if __name__ == "__main__":
         builder = build.ProjectBuilder(package_path, runner=_runner)
         builder.build("wheel", "dist")
 
-        # 6. Copy wheels back
+        # 7. Copy wheels back
         print("-- Copying wheels to dist/")
         dist_path = Path("dist")
         if not dist_path.is_dir():
diff --git a/doc/changelogs/changes-6.6.3 b/doc/changelogs/changes-6.6.3
new file mode 100644 (file)
index 0000000..8875649
--- /dev/null
@@ -0,0 +1,60 @@
+Qt for Python 6.6.3 is a bug-fix release.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qtforpython/
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+*                                  PySide6                                 *
+****************************************************************************
+
+ - pyside6-project now also builds translation (.qm) files.
+ - [PYSIDE-769]  QtAsyncio: Fix a missing attribute error on Windows. Fix
+ - [PYSIDE-2641] QtAsyncio.run() not returning the result of a coroutine. It
+                 is now possible to disable the signal handler for SIGINT by
+                 passing a parameter to run(). The loop policy is reset after
+                 run() finishes.
+ - [PYSIDE-1112] Documentation: The list of tools has been updated.
+ - [PYSIDE-1112] Documentation: A page on the pyside6-project tool
+                 has been added.
+ - [PYSIDE-1955] Type hints: Add support for classmethods
+ - [PYSIDE-2206] An exit crash of the audiooutput example has been fixed.
+ - [PYSIDE-2263] Type hints: Support for class attributes has been added.
+ - [PYSIDE-2468] Documentation on the PySide6 Permission API has been added.
+ - [PYSIDE-2590] Some fixes have been made be able to cope with namespaced Qt
+                 builds.
+ - [PYSIDE-2599] The conversion of QVariant<->QMatrix<n>x<m> has been fixed.
+ - [PYSIDE-2603] Documentation: A broken link to the widget styling tutorial
+                 has been fixed.
+ - [PYSIDE-2610] Inheritance from QAbstractTextureImage/
+                 QTextureImageDataGenerator has been fixed.
+ - [PYSIDE-2612] Plain CMake builds with Limited API on Windows have been
+                 fixed.
+ - [PYSIDE-2613] Connecting to signals with QFlags<> arguments has been fixed.
+ - [PYSIDE-2627] A regression breaking calling Signal.connect() with
+                 QObject-derived callables has been fixed.
+ - [PYSIDE-2628] A crash using struct.unpack() on a QByteArray with
+                 Limited API has been fixed.
+ - [PYSIDE-2638] A crash when adding None to a QLayout has been fixed.
+ - [PYSIDE-2639] macOS: A segmentation fault in QLocale.system() has been
+                 fixed.
+ - [PYSIDE-2640] pyside6-qml now uses a QQuickView when the rootobject is a
+                 QQuickItem.
+
+****************************************************************************
+*                                  Shiboken6                               *
+****************************************************************************
+
+ - [PYSIDE-2505] Command line option parsing has been improved to skip empty
+                 tokens when in include paths.
+ - [PYSIDE-2619] An ODR violation in shibobken code has been fixed, enabling
+                 LTO.
diff --git a/doc/changelogs/changes-6.7.0 b/doc/changelogs/changes-6.7.0
new file mode 100644 (file)
index 0000000..cf51571
--- /dev/null
@@ -0,0 +1,127 @@
+Qt for Python 6.7.0 is a minor release.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qtforpython/
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+*                                  PySide6                                 *
+****************************************************************************
+
+ - setup.py now uses CMake Unity Build Mode by default.
+ - The namespace QAudio has been renamed to QtAudio in Qt 6.7. An alias
+   has been created, but it may not work in all cases.
+ - pyside6-project now has an lupdate mode updating translation files (.ts)
+   from the sources.
+ - Python code has been updated to be free of flake8 warnings using
+   a custom configuration.
+ - For deployment, the supported version of Nuitka has been raised to 2.1.0.
+ - singleShot timers with a timeout of 0 now call the C++ function (which
+   directly calls QMetaObject::invokeMethod) instead of manually creating and
+   starting a timer object, slightly improving performance.
+ - [PYSIDE-769]  QtAsyncio: Fix a missing attribute error on Windows. Fix
+ - [PYSIDE-2641] QtAsyncio.run() not returning the result of a coroutine. It
+                 is now possible to disable the signal handler for SIGINT by
+                 passing a parameter to run(). The loop policy is reset after
+                 run() finishes.
+ - [PYSIDE-838]  Functions qCompress/qUncompress() taking a PyBuffer/len
+                 arguments have been fixed.
+ - [PYSIDE-1106] Documentation: Decorators, global functions and enumerations
+                 are now documented add indexed from the module page. The class
+                 documentation now uses more sphinx domain directives.
+                 Pages for all tools have been added. The order of the examples
+                 list has been changed to show relevant examples first.
+ - [PYSIDE-1275] QObject.disconnect() now returns False with a warning instead
+                 of raising an exception for non-fatal cases.
+ - [PYSIDE-1612] Deployment: Issues when using pyenv have been fixed. The
+                 finding of dependent modules has been improved. On Windows,
+                 this now requires the dumpbin tool, which is added to the path
+                 by calling the vcvarsall.bat script of Microsoft Visual
+                 Studio.
+ - [PYSIDE-1612] Android Deployment: The NDK version in the tool has been
+                 updated. Python has been updated to 3.11. CMake version 3.23
+                 is now required. The wheels are no longer built with
+                 --limited-api. The generated pysidedeploy.spec has an explicit
+                 group called `android` which stores the wheels and plugins.
+ - [PYSIDE-1906] Hash value calculation has been optimized.
+ - [PYSIDE-2206] The colorpaletteclient demo as well as the hellographs and
+                 simplerhiwidget examples have been added.
+ - [PYSIDE-2215] Intersphinx support has been improved.
+ - [PYSIDE-2280] A type for os.PathLike type hints has been added.
+ - [PYSIDE-2404] Application startup time has been significantly decreased
+                 by creating the types on demand. The importing of numpy
+                 has also been deferred since it caused quite some delay.
+ - [PYSIDE-2432] A static create() function for decorated QML singletons
+                 has been added.
+ - [PYSIDE-2484] The QML type registration code has been ported to use
+                 RegisterTypeAndRevisions.
+ - [PYSIDE-2535] Obtaining DBUS properties from QDBusInterface has been fixed.
+                 As a consequence though, it is no longer possible to derive a
+                 Python class with signals/slots from QDBusInterface.
+ - [PYSIDE-2504] Documentation: Option 'build_rst_docs' has been deprecated in
+                 favor of 'build_base_docs'.
+ - [PYSIDE-2524] It is now possible to connect signals to slots/lambdas with
+                 more arguments provided they have default parameters.
+ - [PYSIDE-2524] The signal connection code has been optimized.
+ - [PYSIDE-2543] QtQuickTest has been added.
+ - [PYSIDE-2576] Documentation: The extendedexplorer tutorial has been improved.
+ - [PYSIDE-2590] Some fixes have been made be able to cope with namespaced Qt
+                 builds.
+ - [PYSIDE-2610] The QTextureImageData methods returning an enumeration of
+                 QOpenGLTexture have been added.
+ - [PYSIDE-2605] An error about the C++ object being deleted when calling
+                 QWidget.style() in an embedded application has been fixed.
+ - [PYSIDE-2468] Deployment: Support for the Qt permission API has been added.
+                 macOS bundle applications are now created.
+ - [PYSIDE-2597] Desktop Deployment: The the plugins included have been
+                 optimized.
+ - [PYSIDE-2633] C++ typedefs of container instantiations are now
+                 registered in Python under their name, making possible
+                 to decorate slots with those names (for example,
+                 "QRemoteObjectSourceLocation").
+ - [PYSIDE-2639] Segmentation fault with QLocale.system() has been fixed.
+ - [PYSIDE-2652] A bug when passing values of unsigned long long type
+                 exceeding the long long maximum value to float
+                 parameters has been fixed.
+ - [PYSIDE-2663] A crash in QtWebEngine browsing https://outlook.com has been
+                 fixed.
+ - [PYSIDE-2668] A bug when comparing QOperatingSystemVersion::OSType
+                 has been fixed.
+ - [QTBUG-119785] The Filesystemexplorer-example has been updated.
+
+****************************************************************************
+*                                  Shiboken6                               *
+****************************************************************************
+
+ - [PYSIDE-31]   Shiboken.wrapInstance() now returns existing instances
+                 (preserving ids).
+ - [PYSIDE-560]  libshiboken/Limited API: No longer needed PyTypeObject slots
+                 have been disabled in the PyTypeObject helper struct.
+ - [PYSIDE-1106] A typesystem attribute providing a hint to a documentation
+                 file has been added to function/enum type entries
+                 (for globals).
+ - [PYSIDE-1106] Documentation can now be injected from separate .rst files.
+ - [PYSIDE-1106] Documentation injected into classes with "append" will now
+                 be appended to the class description instead of being written
+                 at the end of the page.
+ - [PYSIDE-1106] Documentation: It is now possible to inject documentation
+                 for parameters of added functions.
+ - [PYSIDE-2230] Python 3.12: Hidden Type Extensions according to PEP 697
+                 are now used instead of shadow dictionaries.
+ - [PYSIDE-2404] The generated type index constants are no longer in
+                 uppercase. Uppercase is retained until deprecation in
+                 PySide7.
+ - [PYSIDE-2447] A typesystem attribute to generate submodules has been added.
+ - [PYSIDE-2535] Generating the Qt meta object functions handling the PySide6
+                 signals can now be disabled by a typesystem attribute. This
+                 is useful for classes using dynamic meta objects, for
+                 example QDBusInterface.
diff --git a/doc/changelogs/changes-6.7.1 b/doc/changelogs/changes-6.7.1
new file mode 100644 (file)
index 0000000..66263ed
--- /dev/null
@@ -0,0 +1,61 @@
+Qt for Python 6.7.1 is a bug-fix release.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qtforpython/
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+*                                  PySide6                                 *
+****************************************************************************
+
+ - [PYSIDE-487]  A number of missing classes have been added.
+ - [PYSIDE-2629] Tooling: pyside6-qsb, pyside6-balsam and pyside6-balsamui
+                 have been added.
+ - [PYSIDE-2644] QtAsyncio: An issue with tasks with loop not cancelling
+                 has been fixed.
+ - [PYSIDE-2663] A crash when browsing https://outlook.com has been fixed.
+ - [PYSIDE-2665] A syntax error in the pyi-files has been fixed.
+ - [PYSIDE-2668] The comparison of QOperatingSystemVersion.OSType has been
+                 fixed.
+ - [PYSIDE-2675] Lazy Load: An issue with polymorphic classes has been
+                 fixed.
+ - [PYSIDE-2676] A crash with Python 3.12 when creating classes from
+                 meta classes has been fixed.
+ - [PYSIDE-2685] An error in the pyi-files related to the import of
+                 NoneType has been fixed.
+ - [PYSIDE-2686] Missing imports for types of return values
+                 have been added to the  pyi-files.
+ - [PYSIDE-2698] A crash when querying the size of QtQml.ListProperty
+                 has been fixed and documentation for QtQml.ListProperty
+                 has been added.
+ - [PYSIDE-2705] Warnings about failures of QObject.disconnect() can
+                 now be suppressed.
+ - [PYSIDE-2709] A bug using legacy qmlRegisterType() for class hierarchies
+                 has been fixed.
+ - [QTBUG-123997] Multimedia: The renaming of the namespace QAudio to
+                  QtAudio has been undone following a revert in Qt.
+
+****************************************************************************
+*                                  Shiboken6                               *
+****************************************************************************
+
+ - [PYSIDE-2590] An attribute for global inline namespace scopes has been
+                 added.
+ - [PYSIDE-2602] Generate Python override code for added virtuals
+ - [PYSIDE-2602] Support for virtual functions with return type
+                 modifications has been added and the function
+                 QWebEnginePage.javaScriptPrompt()
+                 has been fixed accordingly.
+ - [PYSIDE-2675] A code snippet placeholder for the base class for
+                 polymorphic-id-expressions has been added, fixing
+                 a potentially undefined behavior when using the
+                 derived classes.
diff --git a/doc/changelogs/changes-6.7.2 b/doc/changelogs/changes-6.7.2
new file mode 100644 (file)
index 0000000..44015f2
--- /dev/null
@@ -0,0 +1,50 @@
+Qt for Python 6.7.2 is a bug-fix release.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qtforpython/
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+*                                  PySide6                                 *
+****************************************************************************
+
+ - [PYSIDE-1612] Android Deployment now used the development branch of p4a.
+ - [PYSIDE-2712] Type hints: Modified types are no longer considered
+                 as eligible implicit conversions.
+ - [PYSIDE-2745] Exceptions occurring in a slot connected to a
+                 0-delay singleShot timer signal are no longer suppressed.
+ - [PYSIDE-2747] Running on Fedora 40 with Python 3.12.3-2 has been fixed.
+ - [PYSIDE-2748] Type hints: QTranslator.translate() has been fixed.
+ - [PYSIDE-2749] Lazy Load: A performance regression showing in Qt event
+                 filters has been fixed.
+ - [PYSIDE-2750] Qt6VirtualKeyboardSettings have been added to the wheel.
+ - [PYSIDE-2756] Type hints: The return type of QItemSelection.__init__()
+                 has been fixed.
+ - [PYSIDE-2758] QQuickWebEngineProfile.setUrlRequestInterceptor()
+                 has been added.
+ - [PYSIDE-2759] The ownership of cache object passed to
+                 QNetworkAccessManager.setCache() has been fixed.
+ - [PYSIDE-2762] Type hints: The return type of
+                 QModelIndex.internalPointer() has been fixed.
+ - [PYSIDE-2767] Type hints: An error checking the property decorator
+                 has been fixed.
+ - [PYSIDE-2768] Type hints: smart pointer signatures have been fixed.
+
+****************************************************************************
+*                                  Shiboken6                               *
+****************************************************************************
+
+ - [PYSIDE-2764] The missing declaration of the deprecated variable
+                 cppApiVariableNameOld has been added to the generated
+                 headers.
+ - [PYSIDE-2769] Finding the clang include directories on
+                 manylinux_2_28_x86_64 has been fixed.
index 598d9b4bd1f5158716c9213ccfe12b384b8e5a55..c5d7fc2fe9e7c14de54e274acb7589b310ae7d55 100644 (file)
@@ -131,4 +131,4 @@ if __name__ == "__main__":
 
     main_window.show()
 
-    QtAsyncio.run(eratosthenes.start())
+    QtAsyncio.run(eratosthenes.start(), handle_sigint=True)
index 4545f35d51e710102e98eb55addc11230d7b258a..a6c4708b3d90af9e64d265ccddc34b0ac1ab357c 100644 (file)
@@ -1,7 +1,7 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
 
-from PySide6.QtCore import (Qt, QObject, Signal, Slot)
+from PySide6.QtCore import Qt
 from PySide6.QtWidgets import (QApplication, QLabel, QMainWindow, QPushButton, QVBoxLayout, QWidget)
 
 import PySide6.QtAsyncio as QtAsyncio
@@ -12,8 +12,6 @@ import sys
 
 class MainWindow(QMainWindow):
 
-    start_signal = Signal()
-
     def __init__(self):
         super().__init__()
 
@@ -26,37 +24,17 @@ class MainWindow(QMainWindow):
         layout.addWidget(self.text, alignment=Qt.AlignmentFlag.AlignCenter)
 
         async_trigger = QPushButton(text="What is the question?")
-        async_trigger.clicked.connect(self.async_start)
+        async_trigger.clicked.connect(lambda: asyncio.ensure_future(self.set_text()))
         layout.addWidget(async_trigger, alignment=Qt.AlignmentFlag.AlignCenter)
 
-    @Slot()
-    def async_start(self):
-        self.start_signal.emit()
-
     async def set_text(self):
         await asyncio.sleep(1)
         self.text.setText("What do you get if you multiply six by nine?")
 
 
-class AsyncHelper(QObject):
-
-    def __init__(self, worker, entry):
-        super().__init__()
-        self.entry = entry
-        self.worker = worker
-        if hasattr(self.worker, "start_signal") and isinstance(self.worker.start_signal, Signal):
-            self.worker.start_signal.connect(self.on_worker_started)
-
-    @Slot()
-    def on_worker_started(self):
-        asyncio.ensure_future(self.entry())
-
-
 if __name__ == "__main__":
     app = QApplication(sys.argv)
     main_window = MainWindow()
-    async_helper = AsyncHelper(main_window, main_window.set_text)
-
     main_window.show()
 
-    QtAsyncio.run()
+    QtAsyncio.run(handle_sigint=True)
index 0740afa7a5b9539706d8fb7db5af2448ac9b12d5..b443b2bc24a91a828c7ee5fefcbd2f4c453cc707 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'device.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.2.3
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
index fc1f45fef06cd67e2e4f261d92fff4c61d180752..ccc36677a4b97b59cdb17aed20cd0d74e7e0e25f 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'service.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.2.3
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
index 421446c8e8dd47e607b523cfd37c731efabcc00b..7bf60bbc50a6aba6d1d402f4a678366c3fbcd140 100644 (file)
@@ -7,9 +7,9 @@ from PySide6.QtBluetooth import QBluetoothLocalDevice
 from PySide6.QtQml import QmlElement
 from PySide6.QtCore import QObject, Property, Signal, Slot, Qt
 
-from heartrate_global import simulator, is_android
+from heartrate_global import simulator, is_android, error_not_nuitka
 
-if is_android:
+if is_android or sys.platform == "darwin":
     from PySide6.QtCore import QBluetoothPermission
 
 # To be used on the @QmlElement decorator
@@ -58,7 +58,8 @@ class ConnectionHandler(QObject):
         self.deviceChanged.emit()
 
     def initLocalDevice(self):
-        if is_android:
+        if is_android or sys.platform == "darwin":
+            error_not_nuitka()
             permission = QBluetoothPermission()
             permission.setCommunicationModes(QBluetoothPermission.Access)
             permission_status = qApp.checkPermission(permission)  # noqa: F821
index 5cabd1b5bc108d42d6039eac900c8921dd802f29..e581d12ec02209da4da25dce2143d4b3e2ecbe42 100644 (file)
@@ -1,5 +1,6 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+import sys
 
 from PySide6.QtBluetooth import (QBluetoothDeviceDiscoveryAgent,
                                  QBluetoothDeviceInfo)
@@ -8,9 +9,9 @@ from PySide6.QtCore import QTimer, Property, Signal, Slot, Qt
 
 from bluetoothbaseclass import BluetoothBaseClass
 from deviceinfo import DeviceInfo
-from heartrate_global import simulator, is_android
+from heartrate_global import simulator, is_android, error_not_nuitka
 
-if is_android:
+if is_android or sys.platform == "darwin":
     from PySide6.QtCore import QBluetoothPermission
 
 # To be used on the @QmlElement decorator
@@ -46,7 +47,8 @@ class DeviceFinder(BluetoothBaseClass):
 
     @Slot()
     def startSearch(self):
-        if is_android:
+        if is_android or sys.platform == "darwin":
+            error_not_nuitka()
             permission = QBluetoothPermission()
             permission.setCommunicationModes(QBluetoothPermission.Access)
             permission_status = qApp.checkPermission(permission)  # noqa: F821
index 584c44d21cf013d36ba9584d5b67d7a63156ccf3..de5c37ac3bea1cce0f7505b1708b4e3f8c61d8e7 100644 (file)
@@ -1,7 +1,7 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
 import os
-
+import sys
 
 _simulator = False
 
@@ -17,3 +17,14 @@ def set_simulator(s):
 
 
 is_android = os.environ.get('ANDROID_ARGUMENT')
+
+
+def error_not_nuitka():
+    """Errors and exits for macOS if run in interpreted mode.
+    """
+    is_nuitka = "__compiled__" in globals()
+    if not is_nuitka and sys.platform == "darwin":
+        print("This example does not work on macOS when Python is run in interpreted mode."
+              "For this example to work on macOS, package the example using pyside6-deploy"
+              "For more information, read `Notes for Developer` in the documentation")
+        sys.exit(0)
index 231813a67163eb9d54458ca52b7d920404037228..711615b3e70df1f24b0283a9dab500216d1418a0 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'themewidget.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.2.3
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -64,7 +64,7 @@ class Ui_ThemeWidgetForm(object):
 
         self.horizontalLayout.addWidget(self.antialiasCheckBox)
 
-        self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+        self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
 
         self.horizontalLayout.addItem(self.horizontalSpacer)
 
index 035b60d68109669cfb5c40920d4800e25107b51b..2cd544f401f80beb0b7ab1a806f4f3964c28d718 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'dialog.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.2.3
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
diff --git a/examples/demos/colorpaletteclient/ColorPalette/ColorDialogDelete.qml b/examples/demos/colorpaletteclient/ColorPalette/ColorDialogDelete.qml
new file mode 100644 (file)
index 0000000..0fd26e4
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import QtExampleStyle
+
+Popup {
+    id: colorDeleter
+    padding: 10
+    modal: true
+    focus: true
+    anchors.centerIn: parent
+    closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+    signal deleteClicked(int cid)
+
+    property int colorId: -1
+
+    property string colorName: ""
+
+    function maybeDelete(color_id, name) {
+        colorName = name
+        colorId = color_id
+        open()
+    }
+
+
+    ColumnLayout {
+        anchors.fill: parent
+        spacing: 10
+
+        Text {
+            color: "#222222"
+            text: qsTr("Delete Color?")
+            font.pixelSize: 16
+            font.bold: true
+        }
+
+        Text {
+            color: "#222222"
+            text: qsTr("Are you sure, you want to delete color") + " \"" + colorDeleter.colorName + "\"?"
+            font.pixelSize: 12
+        }
+
+        RowLayout {
+            Layout.fillWidth: true
+            spacing: 10
+
+            Button {
+                Layout.fillWidth: true
+                text: qsTr("Cancel")
+                onClicked: colorDeleter.close()
+            }
+
+            Button {
+                Layout.fillWidth: true
+                text: qsTr("Delete")
+
+                buttonColor: "#CC1414"
+                textColor: "#FFFFFF"
+
+                onClicked: {
+                    colorDeleter.deleteClicked(colorDeleter.colorId)
+                    colorDeleter.close()
+                }
+            }
+       }
+    }
+}
diff --git a/examples/demos/colorpaletteclient/ColorPalette/ColorDialogEditor.qml b/examples/demos/colorpaletteclient/ColorPalette/ColorDialogEditor.qml
new file mode 100644 (file)
index 0000000..cba6e5a
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Dialogs
+
+import QtExampleStyle
+
+Popup {
+    id: colorEditor
+    // Popup for adding or updating a color
+    padding: 10
+    modal: true
+    focus: true
+    anchors.centerIn: parent
+    closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+    signal colorAdded(string name, string color, string pantone_value)
+    signal colorUpdated(string name, string color, string pantone_value, int cid)
+
+    property bool newColor: true
+    property int colorId: -1
+    property alias currentColor: colordialogButton.buttonColor
+
+    function createNewColor() {
+        newColor = true
+        colorNameField.text = "cute green"
+        colorRGBField.text = "#41cd52"
+        colorPantoneField.text = "PMS 802C"
+        open()
+    }
+
+    function updateColor(color_id, name, color, pantone_value) {
+        newColor = false
+        colorNameField.text = name
+        currentColor = color
+        colorPantoneField.text = pantone_value
+        colorId = color_id
+        open()
+    }
+
+    ColorDialog {
+        id: colorDialog
+        title: qsTr("Choose a color")
+        onAccepted: {
+            colorEditor.currentColor = Qt.color(colorDialog.selectedColor)
+            colorDialog.close()
+        }
+        onRejected: {
+            colorDialog.close()
+        }
+    }
+
+    ColumnLayout {
+        anchors.fill: parent
+        spacing: 10
+
+        GridLayout {
+            columns: 2
+            rowSpacing: 10
+            columnSpacing: 10
+
+            Label {
+                text: qsTr("Color Name")
+            }
+            TextField {
+                id: colorNameField
+                padding: 10
+            }
+
+            Label {
+                text: qsTr("Pantone Value")
+            }
+            TextField {
+                id: colorPantoneField
+                padding: 10
+            }
+
+            Label {
+                text: qsTr("Rgb Value")
+            }
+
+            TextField {
+                id: colorRGBField
+                text: colorEditor.currentColor.toString()
+                readOnly: true
+                padding: 10
+            }
+        }
+
+        Button {
+            id: colordialogButton
+            Layout.fillWidth: true
+            Layout.preferredHeight: 30
+            text: qsTr("Set Color")
+            textColor: isColorDark(buttonColor) ? "#E6E6E6" : "#191919"
+
+            onClicked: colorDialog.open()
+
+            function isColorDark(color) {
+                return (0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b) < 0.5;
+            }
+        }
+
+        RowLayout {
+            Layout.fillWidth: true
+            spacing: 10
+
+            Button {
+                text: qsTr("Cancel")
+                onClicked: colorEditor.close()
+                Layout.fillWidth: true
+            }
+
+            Button {
+                Layout.fillWidth: true
+                text: colorEditor.newColor ? qsTr("Add") : qsTr("Update")
+
+                buttonColor: "#2CDE85"
+                textColor: "#FFFFFF"
+
+                onClicked: {
+                    if (colorEditor.newColor) {
+                        colorEditor.colorAdded(colorNameField.text,
+                                               colorRGBField.text,
+                                               colorPantoneField.text)
+                    } else {
+                        colorEditor.colorUpdated(colorNameField.text,
+                                                 colorRGBField.text,
+                                                 colorPantoneField.text,
+                                                 colorEditor.colorId)
+                    }
+                    colorEditor.close()
+                }
+            }
+        }
+    }
+}
diff --git a/examples/demos/colorpaletteclient/ColorPalette/ColorView.qml b/examples/demos/colorpaletteclient/ColorPalette/ColorView.qml
new file mode 100644 (file)
index 0000000..c6ad36f
--- /dev/null
@@ -0,0 +1,381 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Effects
+import QtQuick.Shapes
+
+import QtExampleStyle
+import ColorPalette
+
+Item {
+    id: root
+    required property BasicLogin loginService
+    required property PaginatedColorsResource colors
+    required property PaginatedColorUsersResource colorViewUsers
+
+    ColorDialogEditor {
+        id: colorPopup
+        onColorAdded: (colorNameField, colorRGBField, colorPantoneField) => {
+            root.colors.add({"name" : colorNameField,
+                        "color" : colorRGBField,
+                        "pantone_value" : colorPantoneField})
+        }
+
+        onColorUpdated: (colorNameField, colorRGBField, colorPantoneField, cid) => {
+            root.colors.update({"name" : colorNameField,
+                        "color" : colorRGBField,
+                        "pantone_value" : colorPantoneField},
+                        cid)
+        }
+    }
+
+    ColorDialogDelete {
+        id: colorDeletePopup
+        onDeleteClicked: (cid) => {
+            root.colors.remove(cid)
+        }
+    }
+
+    ColumnLayout {
+        // The main application layout
+        anchors.fill :parent
+
+        ToolBar {
+            Layout.fillWidth: true
+            Layout.minimumHeight: 25 + 4
+
+            UserMenu {
+                id: userMenu
+
+                userMenuUsers: root.colorViewUsers
+                userLoginService: root.loginService
+            }
+
+            RowLayout {
+                anchors.fill: parent
+                Text {
+                    text: qsTr("QHTTP Server")
+                    font.pixelSize: 8
+                    color: "#667085"
+                }
+                Item { Layout.fillWidth: true }
+
+                AbstractButton {
+                    id: loginButton
+                    Layout.preferredWidth: 25
+                    Layout.preferredHeight: 25
+                    Item {
+                        id: userImageCliped
+                        anchors.left: parent.left
+                        anchors.verticalCenter: parent.verticalCenter
+                        width: 25
+                        height: 25
+
+                        Image {
+                            id: userImage
+                            anchors.fill: parent
+                            source: getCurrentUserImage()
+                            visible: false
+
+                            function getCurrentUserImage() {
+                                if (root.loginService.loggedIn)
+                                    return users.avatarForEmail(loginService.user)
+                                return "qrc:/qt/qml/ColorPalette/icons/user.svg";
+                            }
+                        }
+
+                        Image {
+                            id: userMask
+                            source: "qrc:/qt/qml/ColorPalette/icons/userMask.svg"
+                            anchors.fill: userImage
+                            anchors.margins: 4
+                            visible: false
+                        }
+
+                        MultiEffect {
+                            source: userImage
+                            anchors.fill: userImage
+                            maskSource: userMask
+                            maskEnabled: true
+                        }
+                    }
+
+                    onClicked: {
+                        userMenu.open()
+                        var pos = mapToGlobal(Qt.point(x, y))
+                        pos = userMenu.parent.mapFromGlobal(pos)
+                        userMenu.x = x - userMenu.width + 25 + 3
+                        userMenu.y = y + 25 + 3
+                    }
+
+                    Shape {
+                       id: bubble
+                       x: -text.width - 25
+                       anchors.margins: 3
+
+                       preferredRendererType: Shape.CurveRenderer
+
+                        visible: !root.loginService.loggedIn
+
+                       ShapePath {
+                           strokeWidth: 0
+                           fillColor: "#667085"
+                           startX: 5; startY: 0
+                           PathLine { x: 5 + text.width + 6; y: 0 }
+                           PathArc { x: 10 + text.width + 6; y: 5; radiusX: 5; radiusY: 5}
+                           // arrow
+                           PathLine { x: 10 + text.width + 6; y: 8 + text.height / 2 - 6 }
+                           PathLine { x: 10 + text.width + 6 + 6; y: 8 + text.height / 2 }
+                           PathLine { x: 10 + text.width + 6; y: 8 + text.height / 2 + 6}
+                           PathLine { x: 10 + text.width + 6; y: 5 + text.height + 6 }
+                           // end arrow
+                           PathArc { x: 5 + text.width + 6; y: 10 + text.height + 6 ; radiusX: 5; radiusY: 5}
+                           PathLine { x: 5; y: 10 + text.height + 6 }
+                           PathArc { x: 0; y: 5 + text.height + 6 ; radiusX: 5; radiusY: 5}
+                           PathLine { x: 0; y: 5 }
+                           PathArc { x: 5; y: 0 ; radiusX: 5; radiusY: 5}
+                       }
+                       Text {
+                           x: 8
+                           y: 8
+                           id: text
+                           color: "white"
+                           text: qsTr("Log in to edit")
+                           font.bold: true
+                           horizontalAlignment: Qt.AlignHCenter
+                           verticalAlignment: Qt.AlignVCenter
+                       }
+                   }
+                }
+            }
+
+            Image {
+                anchors.centerIn: parent
+                source: "qrc:/qt/qml/ColorPalette/icons/qt.png"
+                fillMode: Image.PreserveAspectFit
+                height: 25
+            }
+
+        }
+        ToolBar {
+            Layout.fillWidth: true
+            Layout.minimumHeight: 32
+
+            RowLayout {
+                anchors.fill: parent
+                Text {
+                    Layout.alignment: Qt.AlignVCenter
+                    text: qsTr("Color Palette")
+                    font.pixelSize: 14
+                    font.bold: true
+                    color: "#667085"
+                }
+
+                Item { Layout.fillWidth: true }
+
+                AbstractButton {
+                    Layout.preferredWidth: 25
+                    Layout.preferredHeight: 25
+                    Layout.alignment: Qt.AlignVCenter
+
+                    Rectangle {
+                        anchors.fill: parent
+                        radius: 4
+                        color: "#192CDE85"
+                        border.color: "#DDE2E8"
+                        border.width: 1
+                    }
+
+                    Image {
+                        source: UIStyle.iconPath("plus")
+                        fillMode: Image.PreserveAspectFit
+                        anchors.fill: parent
+                        sourceSize.width: width
+                        sourceSize.height: height
+
+                    }
+                    visible: root.loginService.loggedIn
+                    onClicked: colorPopup.createNewColor()
+                }
+
+                AbstractButton {
+                    Layout.preferredWidth: 25
+                    Layout.preferredHeight: 25
+                    Layout.alignment: Qt.AlignVCenter
+
+                    Rectangle {
+                        anchors.fill: parent
+                        radius: 4
+                        color: "#192CDE85"
+                        border.color: "#DDE2E8"
+                        border.width: 1
+                    }
+
+                    Image {
+                        source: UIStyle.iconPath("update")
+                        fillMode: Image.PreserveAspectFit
+                        anchors.fill: parent
+                        sourceSize.width: width
+                        sourceSize.height: height
+                    }
+
+                    onClicked: {
+                        root.colors.refreshCurrentPage()
+                        root.colorViewUsers.refreshCurrentPage()
+                    }
+                }
+            }
+        }
+
+
+
+        //! [View and model]
+        ListView {
+            id: colorListView
+
+            model: root.colors.model
+        //! [View and model]
+            footerPositioning: ListView.OverlayFooter
+            spacing: 15
+            clip: true
+
+            Layout.fillHeight: true
+            Layout.fillWidth: true
+
+            header:  Rectangle {
+                height: 32
+                width: parent.width
+                color: "#F0F1F3"
+
+                RowLayout {
+                    anchors.fill: parent
+
+                    component HeaderText : Text {
+                        Layout.alignment: Qt.AlignVCenter
+                        horizontalAlignment: Qt.AlignHCenter
+
+                        font.pixelSize: 12
+                        color: "#667085"
+                    }
+                    HeaderText {
+                        id: headerName
+                        text: qsTr("Color Name")
+                        Layout.preferredWidth: colorListView.width * 0.3
+                    }
+                    HeaderText {
+                        id: headerRgb
+                        text: qsTr("Rgb Value")
+                        Layout.preferredWidth: colorListView.width * 0.25
+                    }
+                    HeaderText {
+                        id: headerPantone
+                        text: qsTr("Pantone Value")
+                        Layout.preferredWidth: colorListView.width * 0.25
+                    }
+                    HeaderText {
+                        id: headerAction
+                        text: qsTr("Action")
+                        Layout.preferredWidth: colorListView.width * 0.2
+                    }
+                }
+            }
+
+            delegate: Item {
+                id: colorInfo
+
+                required property int color_id
+                required property string name
+                required property string color
+                required property string pantone_value
+
+                width: colorListView.width
+                height: 25
+                RowLayout {
+                    anchors.fill: parent
+                    anchors.leftMargin: 5
+                    anchors.rightMargin: 5
+
+                    Rectangle {
+                        id: colorSample
+                        Layout.alignment: Qt.AlignVCenter
+                        implicitWidth: 36
+                        implicitHeight: 21
+                        radius: 6
+                        color: colorInfo.color
+                    }
+
+                    Text {
+                        Layout.preferredWidth: colorInfo.width * 0.3 - colorSample.width
+                        horizontalAlignment: Qt.AlignLeft
+                        leftPadding: 5
+                        text: colorInfo.name
+                    }
+
+                    Text {
+                        Layout.preferredWidth: colorInfo.width * 0.25
+                        horizontalAlignment: Qt.AlignHCenter
+                        text: colorInfo.color
+                    }
+
+                    Text {
+                        Layout.preferredWidth: colorInfo.width * 0.25
+                        horizontalAlignment: Qt.AlignHCenter
+                        text: colorInfo.pantone_value
+                    }
+
+                    Item {
+                        Layout.maximumHeight: 28
+                        implicitHeight: buttonBox.implicitHeight
+                        implicitWidth: buttonBox.implicitWidth
+
+                        RowLayout {
+                            id: buttonBox
+                            anchors.fill: parent
+                            ToolButton {
+                                icon.source: UIStyle.iconPath("delete")
+                                enabled: root.loginService.loggedIn
+                                onClicked: colorDeletePopup.maybeDelete(color_id, name)
+                            }
+                            ToolButton {
+                                icon.source: UIStyle.iconPath("edit")
+                                enabled: root.loginService.loggedIn
+                                onClicked: colorPopup.updateColor(color_id, name, color, pantone_value)
+                            }
+                        }
+                    }
+                }
+            }
+
+            footer: ToolBar {
+                // Paginate buttons if more than one page
+                visible: root.colors.pages > 1
+                implicitWidth: parent.width
+
+                RowLayout {
+                    anchors.fill: parent
+
+                    Item { Layout.fillWidth: true /* spacer */ }
+
+                    Repeater {
+                        model: root.colors.pages
+
+                        ToolButton {
+                            text: page
+                            font.bold: root.colors.page === page
+
+                            required property int index
+                            readonly property int page: (index + 1)
+
+                            onClicked: root.colors.page = page
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/examples/demos/colorpaletteclient/ColorPalette/Main.qml b/examples/demos/colorpaletteclient/ColorPalette/Main.qml
new file mode 100644 (file)
index 0000000..ae1e855
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+
+import ColorPalette
+
+Window {
+    id: window
+    width: 500
+    height: 400
+    visible: true
+    title: qsTr("Color Palette Client")
+
+    enum DataView {
+        UserView = 0,
+        ColorView = 1
+    }
+
+    ServerSelection {
+        id: serverview
+        anchors.fill: parent
+        onServerSelected: {colorview.visible = true; serverview.visible = false}
+        colorResources: colors
+        restPalette: paletteService
+        colorUsers: users
+    }
+
+    ColorView {
+        id: colorview
+        anchors.fill: parent
+        visible: false
+        loginService: colorLogin
+        colors: colors
+        colorViewUsers: users
+    }
+
+    //! [RestService QML element]
+    RestService {
+        id: paletteService
+
+        PaginatedColorUsersResource {
+            id: users
+            path: "/api/users"
+        }
+
+        PaginatedColorsResource {
+            id: colors
+            path: "/api/unknown"
+        }
+
+        BasicLogin {
+            id: colorLogin
+            loginPath: "/api/login"
+            logoutPath: "/api/logout"
+        }
+    }
+    //! [RestService QML element]
+
+}
diff --git a/examples/demos/colorpaletteclient/ColorPalette/ServerSelection.qml b/examples/demos/colorpaletteclient/ColorPalette/ServerSelection.qml
new file mode 100644 (file)
index 0000000..c170773
--- /dev/null
@@ -0,0 +1,241 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import ColorPalette
+import QtExampleStyle
+
+pragma ComponentBehavior: Bound
+
+Item {
+    id: root
+    // A popup for selecting the server URL
+
+    signal serverSelected()
+
+    required property PaginatedColorsResource colorResources
+    required property PaginatedColorUsersResource colorUsers
+    required property RestService restPalette
+
+    Connections {
+        target: root.colorResources
+        // Closes the URL selection popup once we have received data successfully
+        function onDataUpdated() {
+            fetchTester.stop()
+            root.serverSelected()
+        }
+    }
+
+
+    ListModel {
+        id: server
+        ListElement {
+            title: qsTr("Public REST API Test Server")
+            url: "https://reqres.in"
+            icon: "qrc:/qt/qml/ColorPalette/icons/testserver.png"
+        }
+        ListElement {
+            title: qsTr("Qt-based REST API server")
+            url: "http://127.0.0.1:49425"
+            icon: "qrc:/qt/qml/ColorPalette/icons/qt.png"
+        }
+    }
+
+
+    ColumnLayout {
+        anchors.fill: parent
+        anchors.margins: 20
+        spacing: 10
+
+        Image {
+            Layout.alignment: Qt.AlignHCenter
+            source: "qrc:/qt/qml/ColorPalette/icons/qt.png"
+            fillMode: Image.PreserveAspectFit
+            Layout.preferredWidth: 20
+        }
+
+        Label {
+            text: qsTr("Choose a server")
+            Layout.alignment: Qt.AlignHCenter
+            font.pixelSize: 24
+        }
+
+        component ServerListDelegate: Rectangle {
+            id: serverListDelegate
+            required property string title
+            required property string url
+            required property string icon
+            required property int index
+
+            radius: 10
+            color: "#00000000"
+
+            border.color: ListView.view.currentIndex === index ? "#2CDE85" : "#E0E2E7"
+            border.width: 2
+
+            implicitWidth: 180
+            implicitHeight: 100
+
+            Rectangle {
+                id: img
+                anchors.left: parent.left
+                anchors.top: parent.top
+                anchors.topMargin: 10
+                anchors.leftMargin: 20
+
+                width: 30
+                height: 30
+                radius: 200
+                border. color: "#E7F4EE"
+                border.width: 5
+
+                Image {
+                        anchors.centerIn: parent
+                        source: serverListDelegate.icon
+                        width: 15
+                        height: 15
+                        fillMode: Image.PreserveAspectFit
+                        smooth: true
+                    }
+                }
+
+                Text {
+                    text: parent.url
+
+                    anchors.left: parent.left
+                    anchors.top: img.bottom
+                    anchors.topMargin: 10
+                    anchors.leftMargin: 20
+                    color: "#667085"
+                    font.pixelSize: 13
+                }
+                Text {
+                    text: parent.title
+
+                    anchors.horizontalCenter: parent.horizontalCenter
+                    anchors.bottom: parent.bottom
+                    anchors.bottomMargin: 10
+                    color: "#222222"
+                    font.pixelSize: 11
+                    font.bold: true
+                }
+
+                MouseArea {
+                anchors.fill: parent
+                onClicked: serverList.currentIndex = serverListDelegate.index;
+            }
+        }
+
+        ListView {
+            id: serverList
+            Layout.alignment: Qt.AlignHCenter
+            Layout.minimumWidth: 180 * server.count + 20
+            Layout.minimumHeight: 100
+            orientation: ListView.Horizontal
+
+            model: server
+            spacing: 20
+
+            delegate: ServerListDelegate {}
+        }
+
+        Button {
+            Layout.alignment: Qt.AlignHCenter
+            text: restPalette.sslSupported ? qsTr("Connect (SSL)") : qsTr("Connect")
+
+            buttonColor: "#2CDE85"
+            textColor: "#FFFFFF"
+
+            onClicked: {
+                busyIndicatorPopup.title = (serverList.currentItem as ServerListDelegate).title
+                busyIndicatorPopup.icon = (serverList.currentItem as ServerListDelegate).icon
+                busyIndicatorPopup.open()
+
+                fetchTester.test((serverList.currentItem  as ServerListDelegate).url)
+            }
+        }
+
+        Timer {
+            id: fetchTester
+            interval: 2000
+
+            function test(url) {
+                root.restPalette.url = url
+                root.colorResources.refreshCurrentPage()
+                root.colorUsers.refreshCurrentPage()
+                start()
+            }
+            onTriggered: busyIndicatorPopup.close()
+        }
+    }
+
+    onVisibleChanged: {if (!visible) busyIndicatorPopup.close();}
+
+    Popup {
+        id: busyIndicatorPopup
+        padding: 10
+        modal: true
+        focus: true
+        anchors.centerIn: parent
+        closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+
+        property alias title: titleText.text
+        property alias icon: titleImg.source
+
+        ColumnLayout {
+            id: fetchIndicator
+            anchors.fill: parent
+
+            RowLayout {
+                Rectangle {
+                    Layout.preferredWidth: 50
+                    Layout.preferredHeight: 50
+                    radius: 200
+                    border. color: "#E7F4EE"
+                    border.width: 5
+
+                    Image {
+                        id: titleImg
+                        anchors.centerIn: parent
+                        width: 25
+                        height: 25
+                        fillMode: Image.PreserveAspectFit
+                    }
+                }
+
+                Label {
+                    id: titleText
+                    text:""
+                    font.pixelSize: 18
+                }
+            }
+
+            RowLayout {
+                Layout.fillWidth: false
+                Layout.alignment: Qt.AlignHCenter
+                BusyIndicator {
+                    running: visible
+                    Layout.fillWidth: true
+                }
+
+                Label {
+                    text: qsTr("Testing URL")
+                    font.pixelSize: 18
+                }
+            }
+
+            Button {
+                Layout.alignment: Qt.AlignHCenter
+                text: qsTr("Cancel")
+                onClicked: {
+                    busyIndicatorPopup.close()
+                }
+            }
+
+        }
+
+    }
+}
diff --git a/examples/demos/colorpaletteclient/ColorPalette/UserMenu.qml b/examples/demos/colorpaletteclient/ColorPalette/UserMenu.qml
new file mode 100644 (file)
index 0000000..6c4b256
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Effects
+
+import QtExampleStyle
+import ColorPalette
+
+Popup {
+    id: userMenu
+
+    required property BasicLogin userLoginService
+    required property PaginatedColorUsersResource userMenuUsers
+
+    width: 280
+    height: 270
+
+    ColumnLayout {
+        anchors.fill: parent
+
+        ListView {
+            id: userListView
+
+            model: userMenu.userMenuUsers.model
+            spacing: 5
+            footerPositioning: ListView.PullBackFooter
+            clip: true
+
+            Layout.fillHeight: true
+            Layout.fillWidth: true
+
+            delegate: Rectangle {
+                id: userInfo
+
+                required property string email
+                required property string avatar
+
+                height: 30
+                width: userListView.width
+
+
+                readonly property bool logged: (email === loginService.user)
+
+                Rectangle {
+                    id: userImageCliped
+                    anchors.left: parent.left
+                    anchors.verticalCenter: parent.verticalCenter
+                    width: 30
+                    height: 30
+
+                    Image {
+                        id: userImage
+                        anchors.fill: parent
+                        source: userInfo.avatar
+                        visible: false
+                    }
+
+                    Image {
+                        id: userMask
+                        source: "qrc:/qt/qml/ColorPalette/icons/userMask.svg"
+                        anchors.fill: userImage
+                        anchors.margins: 4
+                        visible: false
+                    }
+
+                    MultiEffect {
+                        source: userImage
+                        anchors.fill: userImage
+                        maskSource: userMask
+                        maskEnabled: true
+                    }
+                }
+
+                Text {
+                    id: userMailLabel
+                    anchors.left: userImageCliped.right
+                    anchors.verticalCenter: parent.verticalCenter
+                    anchors.margins: 5
+                    text: userInfo.email
+                    font.bold: userInfo.logged
+                }
+
+                ToolButton {
+                    anchors.right: parent.right
+                    anchors.verticalCenter: parent.verticalCenter
+                    anchors.margins: 5
+
+                    icon.source: UIStyle.iconPath(userInfo.logged
+                                 ? "logout" : "login")
+                    enabled: userInfo.logged || !userMenu.userLoginService.loggedIn
+
+                    onClicked: {
+                        if (userInfo.logged) {
+                            userMenu.userLoginService.logout()
+                        } else {
+                            //! [Login]
+                            userMenu.userLoginService.login({"email" : userInfo.email,
+                                                "password" : "apassword",
+                                                "id" : userInfo.id})
+                            //! [Login]
+                            userMenu.close()
+                        }
+                    }
+                }
+
+            }
+            footer: ToolBar {
+                // Paginate buttons if more than one page
+                visible: userMenu.userMenuUsers.pages > 1
+                implicitWidth: parent.width
+
+                RowLayout {
+                    anchors.fill: parent
+
+                    Item { Layout.fillWidth: true /* spacer */ }
+
+                    Repeater {
+                        model: userMenu.userMenuUsers.pages
+
+                        ToolButton {
+                            text: page
+                            font.bold: userMenu.userMenuUsers.page === page
+
+                            required property int index
+                            readonly property int page: (index + 1)
+
+                            onClicked: userMenu.userMenuUsers.page = page
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/examples/demos/colorpaletteclient/ColorPalette/qmldir b/examples/demos/colorpaletteclient/ColorPalette/qmldir
new file mode 100644 (file)
index 0000000..7a153fe
--- /dev/null
@@ -0,0 +1,7 @@
+module ColorPalette
+Main 1.0 Main.qml
+ColorDialogDelete 1.0 ColorDialogDelete.qml
+ColorDialogEditor 1.0 ColorDialogEditor.qml
+ColorView 1.0 ColorView.qml
+ServerSelection 1.0 ServerSelection.qml
+UserMenu 1.0 UserMenu.qml
diff --git a/examples/demos/colorpaletteclient/QtExampleStyle/Button.qml b/examples/demos/colorpaletteclient/QtExampleStyle/Button.qml
new file mode 100644 (file)
index 0000000..6b3f922
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Button {
+    id: control
+
+    property alias buttonColor: rect.color
+    property alias textColor: label.color
+
+    implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+                            implicitContentWidth + leftPadding + rightPadding)
+    implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+                             implicitContentHeight + topPadding + bottomPadding)
+
+    leftPadding: 15
+    rightPadding: 15
+    topPadding: 10
+    bottomPadding: 10
+
+    background: Rectangle {
+        id: rect
+        radius: 8
+        border.color: "#E0E2E7"
+        border.width: 1
+        color: "#FFFFFF"
+    }
+
+    icon.width: 24
+    icon.height: 24
+    icon.color: control.palette.buttonText
+
+    contentItem: IconLabel {
+        id: label
+        spacing: control.spacing
+        mirrored: control.mirrored
+        display: control.display
+
+        icon: control.icon
+        text: control.text
+        font.pixelSize: 14
+        color: "#667085"
+    }
+}
diff --git a/examples/demos/colorpaletteclient/QtExampleStyle/CMakeLists.txt b/examples/demos/colorpaletteclient/QtExampleStyle/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a911f87
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(qtexamplestyle LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+    set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quickcontrols/colorpaletteclient/QtExampleStyle")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick QuickControls2)
+
+set_source_files_properties(UIStyle.qml
+    PROPERTIES
+        QT_QML_SINGLETON_TYPE TRUE
+)
+
+qt_policy(SET QTP0001 NEW)
+qt_add_qml_module(qtexamplestyle
+    URI QtExampleStyle
+    PLUGIN_TARGET qtexamplestyle
+    QML_FILES
+        Button.qml
+        Popup.qml
+        UIStyle.qml
+        TextField.qml
+)
+
+target_link_libraries(qtexamplestyle PUBLIC
+    Qt6::Core
+    Qt6::Gui
+    Qt6::Quick
+    Qt6::QuickControls2
+)
+
+if(UNIX AND NOT APPLE AND CMAKE_CROSSCOMPILING)
+    find_package(Qt6 REQUIRED COMPONENTS QuickTemplates2)
+
+    # Work around QTBUG-86533
+    target_link_libraries(qtexamplestyle PRIVATE Qt6::QuickTemplates2)
+endif()
+
+install(TARGETS qtexamplestyle
+    RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+    BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+    LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qmldir
+    DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/demos/colorpaletteclient/QtExampleStyle/Popup.qml b/examples/demos/colorpaletteclient/QtExampleStyle/Popup.qml
new file mode 100644 (file)
index 0000000..a3132bc
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.Popup {
+    id: control
+
+    implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+                            implicitContentWidth + leftPadding + rightPadding)
+    implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+                             implicitContentHeight + topPadding + bottomPadding)
+
+    leftPadding: 15
+    rightPadding: 15
+    topPadding: 10
+    bottomPadding: 10
+
+    background: Rectangle {
+        id: bg
+        radius: 8
+        border.color: "#E0E2E7"
+        border.width: 2
+        color: "#FFFFFF"
+    }
+}
diff --git a/examples/demos/colorpaletteclient/QtExampleStyle/TextField.qml b/examples/demos/colorpaletteclient/QtExampleStyle/TextField.qml
new file mode 100644 (file)
index 0000000..7db2d4f
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.TextField {
+    id: control
+    placeholderText: ""
+
+    implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, contentWidth + leftPadding + rightPadding)
+    implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+                             contentHeight + topPadding + bottomPadding)
+
+    background: Rectangle {
+        implicitWidth: 200
+        implicitHeight: 40
+        radius: 8
+        color: control.enabled ? "transparent" : "#353637"
+        border.color: "#E0E2E7"
+    }
+}
diff --git a/examples/demos/colorpaletteclient/QtExampleStyle/UIStyle.qml b/examples/demos/colorpaletteclient/QtExampleStyle/UIStyle.qml
new file mode 100644 (file)
index 0000000..3c4741d
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma Singleton
+
+import QtQuick
+
+QtObject {
+    id: uiStyle
+
+    // Font Sizes
+    readonly property int fontSizeXXS: 10
+    readonly property int fontSizeXS: 15
+    readonly property int fontSizeS: 20
+    readonly property int fontSizeM: 25
+    readonly property int fontSizeL: 30
+    readonly property int fontSizeXL: 35
+    readonly property int fontSizeXXL: 40
+
+    // Color Scheme
+    // Green
+    readonly property color colorQtPrimGreen: "#41cd52"
+    readonly property color colorQtAuxGreen1: "#21be2b"
+    readonly property color colorQtAuxGreen2: "#17a81a"
+
+    function iconPath(baseImagePath) {
+        return `qrc:/qt/qml/ColorPalette/icons/${baseImagePath}.svg`
+    }
+}
diff --git a/examples/demos/colorpaletteclient/QtExampleStyle/qmldir b/examples/demos/colorpaletteclient/QtExampleStyle/qmldir
new file mode 100644 (file)
index 0000000..7bdfb44
--- /dev/null
@@ -0,0 +1,5 @@
+module QtExampleStyle
+Button 1.0 Button.qml
+Popup 1.0 Popup.qml
+TextField 1.0 TextField.qml
+singleton UIStyle 1.0 UIStyle.qml
diff --git a/examples/demos/colorpaletteclient/abstractresource.py b/examples/demos/colorpaletteclient/abstractresource.py
new file mode 100644 (file)
index 0000000..3f3a7ed
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtCore import QObject
+from PySide6.QtQml import QmlAnonymous
+
+
+QML_IMPORT_NAME = "ColorPalette"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlAnonymous
+class AbstractResource(QObject):
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.m_manager = None  # QRestAccessManager
+        self.m_api = None  # QNetworkRequestFactory
+
+    def setAccessManager(self, manager):
+        self.m_manager = manager
+
+    def setServiceApi(self, serviceApi):
+        self.m_api = serviceApi
diff --git a/examples/demos/colorpaletteclient/basiclogin.py b/examples/demos/colorpaletteclient/basiclogin.py
new file mode 100644 (file)
index 0000000..b9139c2
--- /dev/null
@@ -0,0 +1,100 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import sys
+from functools import partial
+from dataclasses import dataclass
+
+from PySide6.QtCore import Property, Signal, Slot
+from PySide6.QtNetwork import QHttpHeaders
+from PySide6.QtQml import QmlElement
+
+from abstractresource import AbstractResource
+
+
+tokenField = "token"
+emailField = "email"
+idField = "id"
+
+
+QML_IMPORT_NAME = "ColorPalette"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+class BasicLogin(AbstractResource):
+    @dataclass
+    class User:
+        email: str
+        token: bytes
+        id: int
+
+    userChanged = Signal()
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.m_user = None
+        self.m_loginPath = ""
+        self.m_logoutPath = ""
+        self.m_user = None
+
+    @Property(str, notify=userChanged)
+    def user(self):
+        return self.m_user.email if self.m_user else ""
+
+    @Property(bool, notify=userChanged)
+    def loggedIn(self):
+        return bool(self.m_user)
+
+    @Property(str)
+    def loginPath(self):
+        return self.m_loginPath
+
+    @loginPath.setter
+    def loginPath(self, p):
+        self.m_loginPath = p
+
+    @Property(str)
+    def logoutPath(self):
+        return self.m_logoutPath
+
+    @logoutPath.setter
+    def logoutPath(self, p):
+        self.m_logoutPath = p
+
+    @Slot("QVariantMap")
+    def login(self, data):
+        request = self.m_api.createRequest(self.m_loginPath)
+        self.m_manager.post(request, data, self, partial(self.loginReply, data))
+
+    def loginReply(self, data, reply):
+        self.m_user = None
+        if not reply.isSuccess():
+            print("login: ", reply.errorString(), file=sys.stderr)
+        (json, error) = reply.readJson()
+        if json and json.isObject():
+            json_object = json.object()
+            token = json_object.get(tokenField)
+            if token:
+                email = data[emailField]
+                token = json_object[tokenField]
+                id = data[idField]
+                self.m_user = BasicLogin.User(email, token, id)
+
+        headers = QHttpHeaders()
+        headers.append("token", self.m_user.token if self.m_user else "")
+        self.m_api.setCommonHeaders(headers)
+        self.userChanged.emit()
+
+    @Slot()
+    def logout(self):
+        request = self.m_api.createRequest(self.m_logoutPath)
+        self.m_manager.post(request, b"", self, self.logoutReply)
+
+    def logoutReply(self, reply):
+        if reply.isSuccess():
+            self.m_user = None
+            self.m_api.clearCommonHeaders()  # clears 'token' header
+            self.userChanged.emit()
+        else:
+            print("logout: ", reply.errorString(), file=sys.stderr)
diff --git a/examples/demos/colorpaletteclient/colorpaletteclient.pyproject b/examples/demos/colorpaletteclient/colorpaletteclient.pyproject
new file mode 100644 (file)
index 0000000..d05f7cb
--- /dev/null
@@ -0,0 +1,21 @@
+{
+    "files": [
+        "abstractresource.py",
+        "basiclogin.py",
+        "main.py",
+        "paginatedresource.py",
+        "restservice.py",
+        "colorpaletteclient.qrc",
+        "ColorPalette/ColorDialogDelete.qml",
+        "ColorPalette/ColorDialogEditor.qml",
+        "ColorPalette/ColorView.qml",
+        "ColorPalette/Main.qml",
+        "ColorPalette/ServerSelection.qml",
+        "ColorPalette/UserMenu.qml",
+        "QtExampleStyle/Button.qml",
+        "QtExampleStyle/Popup.qml",
+        "QtExampleStyle/TextField.qml",
+        "QtExampleStyle/UIStyle.qml",
+        "colorpaletteclient.qrc"
+    ]
+}
diff --git a/examples/demos/colorpaletteclient/colorpaletteclient.qrc b/examples/demos/colorpaletteclient/colorpaletteclient.qrc
new file mode 100644 (file)
index 0000000..16260cb
--- /dev/null
@@ -0,0 +1,17 @@
+<RCC>
+    <qresource prefix="/qt/qml/ColorPalette">
+        <file>icons/close.svg</file>
+        <file>icons/delete.svg</file>
+        <file>icons/dots.svg</file>
+        <file>icons/edit.svg</file>
+        <file>icons/login.svg</file>
+        <file>icons/logout.svg</file>
+        <file>icons/ok.svg</file>
+        <file>icons/plus.svg</file>
+        <file>icons/qt.png</file>
+        <file>icons/testserver.png</file>
+        <file>icons/update.svg</file>
+        <file>icons/user.svg</file>
+        <file>icons/userMask.svg</file>
+    </qresource>
+</RCC>
diff --git a/examples/demos/colorpaletteclient/doc/colorpaletteclient.rst b/examples/demos/colorpaletteclient/doc/colorpaletteclient.rst
new file mode 100644 (file)
index 0000000..0dcb91d
--- /dev/null
@@ -0,0 +1,79 @@
+RESTful API client
+==================
+
+Example of how to create a RESTful API QML client.
+
+This example shows how to create a basic QML RESTful API client with an
+imaginary color palette service. The application uses RESTful communication
+with the selected server to request and send data. The REST service is provided
+as a QML element whose child elements wrap the individual JSON data APIs
+provided by the server.
+
+Application functionality
+-------------------------
+
+The example provides the following basic functionalities:
+* Select the server to communicate with
+* List users and colors
+* Login and logout users
+* Modify and create new colors
+
+Server selection
+----------------
+
+At start the application presents the options for the color palette server to communicate
+with. The predefined options are:
+
+* ``https://reqres.in``, a publicly available REST API test service
+* A Qt-based REST API server example in ``QtHttpServer``
+
+Once selected, the RESTful API client issues a test HTTP GET to the color API
+to check if the service is accessible.
+
+One major difference between the two predefined API options is that the
+Qt-based REST API server example is a stateful application which allows
+modifying colors, whereas the ``reqres.in`` is a stateless API testing service.
+In other words, when using the ``reqres.in`` backend, modifying the colors has
+no lasting impact.
+
+The users and colors are paginated resources on the server-side. This means
+that the server provides the data in chunks called pages. The UI listing
+reflects this pagination and views the data on pages.
+
+Viewing the data on UI is done with standard QML views where the model are
+QAbstractListModel-derived classes representing JSON data received from the
+server.
+
+Logging in happens via the login function provided by the login popup. Under
+the hood the login sends a HTTP POST request. Upon receiving a successful
+response the authorization token is extracted from the response, which in turn
+is then used in subsequent HTTP requests which require the token.
+
+Editing and adding new colors is done in a popup. Note that uploading the color
+changes to the server requires that a user has logged in.
+
+REST implementation
+-------------------
+
+The example illustrates one way to compose a REST service from individual resource elements. In
+this example the resources are the paginated user and color resources plus the login service.
+The resource elements are bound together by the base URL (server URL) and the shared network access
+manager.
+
+The basis of the REST service is the RestService QML element whose children items
+compose the actual service.
+
+Upon instantiation the RestService element loops its children elements and sets
+them up to use the same network access manager. This way the individual
+resources share the same access details such as the server URL and
+authorization token.
+
+The actual communication is done with a rest access manager which implements
+some convenience functionality to deal specifically with HTTP REST APIs and
+effectively deals with sending and receiving the ``QNetworkRequest`` and
+``QNetworkReply`` as needed.
+
+.. image:: colorpaletteclient.webp
+   :width: 90%
+   :align: center
+   :alt: RESTful API client
diff --git a/examples/demos/colorpaletteclient/doc/colorpaletteclient.webp b/examples/demos/colorpaletteclient/doc/colorpaletteclient.webp
new file mode 100644 (file)
index 0000000..8f4d9a6
Binary files /dev/null and b/examples/demos/colorpaletteclient/doc/colorpaletteclient.webp differ
diff --git a/examples/demos/colorpaletteclient/icons/close.svg b/examples/demos/colorpaletteclient/icons/close.svg
new file mode 100644 (file)
index 0000000..3a0d4be
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.4501 37.65L10.3501 35.55L21.9001 24L10.3501 12.45L12.4501 10.35L24.0001 21.9L35.5501 10.35L37.6501 12.45L26.1001 24L37.6501 35.55L35.5501 37.65L24.0001 26.1L12.4501 37.65Z" fill="#667085"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/icons/delete.svg b/examples/demos/colorpaletteclient/icons/delete.svg
new file mode 100644 (file)
index 0000000..8f04948
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M13.05 42C12.225 42 11.5187 41.7062 10.9313 41.1188C10.3438 40.5312 10.05 39.825 10.05 39V10.5H8V7.5H17.4V6H30.6V7.5H40V10.5H37.95V39C37.95 39.8 37.65 40.5 37.05 41.1C36.45 41.7 35.75 42 34.95 42H13.05ZM34.95 10.5H13.05V39H34.95V10.5ZM18.35 34.7H21.35V14.75H18.35V34.7ZM26.65 34.7H29.65V14.75H26.65V34.7Z" fill="#667085"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/icons/dots.svg b/examples/demos/colorpaletteclient/icons/dots.svg
new file mode 100644 (file)
index 0000000..49df163
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10.3929 26.4C9.73097 26.4 9.16667 26.1643 8.7 25.6929C8.23333 25.2215 8 24.6548 8 23.9929C8 23.3309 8.2357 22.7666 8.7071 22.3C9.17847 21.8333 9.74513 21.6 10.4071 21.6C11.069 21.6 11.6333 21.8357 12.1 22.3071C12.5667 22.7784 12.8 23.3451 12.8 24.0071C12.8 24.669 12.5643 25.2333 12.0929 25.7C11.6215 26.1666 11.0549 26.4 10.3929 26.4ZM23.9929 26.4C23.331 26.4 22.7667 26.1643 22.3 25.6929C21.8333 25.2215 21.6 24.6548 21.6 23.9929C21.6 23.3309 21.8357 22.7666 22.3071 22.3C22.7785 21.8333 23.3451 21.6 24.0071 21.6C24.669 21.6 25.2333 21.8357 25.7 22.3071C26.1667 22.7784 26.4 23.3451 26.4 24.0071C26.4 24.669 26.1643 25.2333 25.6929 25.7C25.2215 26.1666 24.6549 26.4 23.9929 26.4ZM37.5929 26.4C36.931 26.4 36.3667 26.1643 35.9 25.6929C35.4333 25.2215 35.2 24.6548 35.2 23.9929C35.2 23.3309 35.4357 22.7666 35.9071 22.3C36.3785 21.8333 36.9451 21.6 37.6071 21.6C38.269 21.6 38.8333 21.8357 39.3 22.3071C39.7667 22.7784 40 23.3451 40 24.0071C40 24.669 39.7643 25.2333 39.2929 25.7C38.8215 26.1666 38.2549 26.4 37.5929 26.4Z" fill="#667085"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/icons/edit.svg b/examples/demos/colorpaletteclient/icons/edit.svg
new file mode 100644 (file)
index 0000000..1cfc2a7
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9 39H11.2L33.35 16.85L31.15 14.65L9 36.8V39ZM39.7 14.7L33.3 8.29998L35.4 6.19998C35.9667 5.63331 36.6667 5.34998 37.5 5.34998C38.3333 5.34998 39.0333 5.63331 39.6 6.19998L41.8 8.39998C42.3667 8.96664 42.65 9.66664 42.65 10.5C42.65 11.3333 42.3667 12.0333 41.8 12.6L39.7 14.7ZM37.6 16.8L12.4 42H6V35.6L31.2 10.4L37.6 16.8ZM32.25 15.75L31.15 14.65L33.35 16.85L32.25 15.75Z" fill="#667085"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/icons/login.svg b/examples/demos/colorpaletteclient/icons/login.svg
new file mode 100644 (file)
index 0000000..c8fe5bc
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M24.45 42V39H39V9H24.45V6H39C39.8 6 40.5 6.3 41.1 6.9C41.7 7.5 42 8.2 42 9V39C42 39.8 41.7 40.5 41.1 41.1C40.5 41.7 39.8 42 39 42H24.45ZM20.55 32.75L18.4 30.6L23.5 25.5H6V22.5H23.4L18.3 17.4L20.45 15.25L29.25 24.05L20.55 32.75Z" fill="#667085"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/icons/logout.svg b/examples/demos/colorpaletteclient/icons/logout.svg
new file mode 100644 (file)
index 0000000..91d4fd8
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9 42C8.2 42 7.5 41.7 6.9 41.1C6.3 40.5 6 39.8 6 39V9C6 8.2 6.3 7.5 6.9 6.9C7.5 6.3 8.2 6 9 6H23.55V9H9V39H23.55V42H9ZM33.3 32.75L31.15 30.6L36.25 25.5H18.75V22.5H36.15L31.05 17.4L33.2 15.25L42 24.05L33.3 32.75Z" fill="#667085"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/icons/ok.svg b/examples/demos/colorpaletteclient/icons/ok.svg
new file mode 100644 (file)
index 0000000..506e2d6
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M18.9002 35.7L7.7002 24.5L9.8502 22.35L18.9002 31.4L38.1002 12.2L40.2502 14.35L18.9002 35.7Z" fill="#667085"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/icons/plus.svg b/examples/demos/colorpaletteclient/icons/plus.svg
new file mode 100644 (file)
index 0000000..8183778
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M22.5 38V25.5H10V22.5H22.5V10H25.5V22.5H38V25.5H25.5V38H22.5Z" fill="#667085"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/icons/qt.png b/examples/demos/colorpaletteclient/icons/qt.png
new file mode 100644 (file)
index 0000000..abd3a4f
Binary files /dev/null and b/examples/demos/colorpaletteclient/icons/qt.png differ
diff --git a/examples/demos/colorpaletteclient/icons/qt_attribution.json b/examples/demos/colorpaletteclient/icons/qt_attribution.json
new file mode 100644 (file)
index 0000000..44633c4
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "Id": "colorpaletteclient",
+    "Name": "Selected Material Icons",
+    "QDocModule": "qtdoc",
+    "QtUsage": "Used in Color Palette Client example in QtDoc",
+    "QtParts": [
+        "examples"
+    ],
+    "Files": "close.svg delete.svg dots.svg edit.svg login.svg logout.svg ok.svg update.svg user.svg",
+    "Homepage": "https://fonts.google.com/icons",
+    "License": "Apache License Version 2.0",
+    "LicenseId": "Apache-2.0",
+    "Copyright": "Copyright 2018 Google, Inc. All Rights Reserved."
+}
diff --git a/examples/demos/colorpaletteclient/icons/testserver.png b/examples/demos/colorpaletteclient/icons/testserver.png
new file mode 100644 (file)
index 0000000..0890e5e
Binary files /dev/null and b/examples/demos/colorpaletteclient/icons/testserver.png differ
diff --git a/examples/demos/colorpaletteclient/icons/update.svg b/examples/demos/colorpaletteclient/icons/update.svg
new file mode 100644 (file)
index 0000000..303ff4d
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M24 40C19.5667 40 15.7917 38.4417 12.675 35.325C9.55833 32.2083 8 28.4333 8 24C8 19.5667 9.55833 15.7917 12.675 12.675C15.7917 9.55833 19.5667 8 24 8C26.8333 8 29.3167 8.575 31.45 9.725C33.5833 10.875 35.4333 12.45 37 14.45V8H40V20.7H27.3V17.7H35.7C34.4333 15.7 32.8167 14.0833 30.85 12.85C28.8833 11.6167 26.6 11 24 11C20.3667 11 17.2917 12.2583 14.775 14.775C12.2583 17.2917 11 20.3667 11 24C11 27.6333 12.2583 30.7083 14.775 33.225C17.2917 35.7417 20.3667 37 24 37C26.7667 37 29.3 36.2083 31.6 34.625C33.9 33.0417 35.5 30.95 36.4 28.35H39.5C38.5333 31.85 36.6167 34.6667 33.75 36.8C30.8833 38.9333 27.6333 40 24 40Z" fill="#667085"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/icons/user.svg b/examples/demos/colorpaletteclient/icons/user.svg
new file mode 100644 (file)
index 0000000..ed78238
--- /dev/null
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12Z" fill="#E6E6E6"/>
+<path d="M15.5 12C16.3284 12 17 12.6716 17 13.5V14C17 15.9714 15.1405 18 12 18C8.85951 18 7 15.9714 7 14V13.5C7 12.6716 7.67157 12 8.5 12H15.5ZM15.5 13H8.5C8.22386 13 8 13.2239 8 13.5V14C8 15.4376 9.43216 17 12 17C14.5678 17 16 15.4376 16 14V13.5C16 13.2239 15.7761 13 15.5 13ZM12 5.5C13.5188 5.5 14.75 6.73122 14.75 8.25C14.75 9.76878 13.5188 11 12 11C10.4812 11 9.25 9.76878 9.25 8.25C9.25 6.73122 10.4812 5.5 12 5.5ZM12 6.5C11.0335 6.5 10.25 7.2835 10.25 8.25C10.25 9.2165 11.0335 10 12 10C12.9665 10 13.75 9.2165 13.75 8.25C13.75 7.2835 12.9665 6.5 12 6.5Z" fill="#616161"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/icons/userMask.svg b/examples/demos/colorpaletteclient/icons/userMask.svg
new file mode 100644 (file)
index 0000000..5e3065d
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="30" height="30" viewBox="0 0 30 30" xmlns="http://www.w3.org/2000/svg">
+<ellipse cx="15" cy="15" rx="13" ry="13" fill="black"/>
+</svg>
diff --git a/examples/demos/colorpaletteclient/main.py b/examples/demos/colorpaletteclient/main.py
new file mode 100644 (file)
index 0000000..a249b9f
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+"""PySide6 port of the Qt RESTful API client demo from Qt v6.x"""
+
+import os
+import sys
+from pathlib import Path
+
+from PySide6.QtCore import QUrl
+from PySide6.QtGui import QIcon, QGuiApplication
+from PySide6.QtQml import QQmlApplicationEngine
+
+from basiclogin import BasicLogin  # noqa: F401
+from paginatedresource import PaginatedResource  # noqa: F401
+from restservice import RestService  # noqa: F401
+import rc_colorpaletteclient  # noqa: F401
+
+if __name__ == "__main__":
+    app = QGuiApplication(sys.argv)
+    QIcon.setThemeName("colorpaletteclient")
+
+    engine = QQmlApplicationEngine()
+    app_dir = Path(__file__).parent
+    app_dir_url = QUrl.fromLocalFile(os.fspath(app_dir))
+    engine.addImportPath(os.fspath(app_dir))
+    engine.loadFromModule("ColorPalette", "Main")
+    if not engine.rootObjects():
+        sys.exit(-1)
+
+    ex = app.exec()
+    del engine
+    sys.exit(ex)
diff --git a/examples/demos/colorpaletteclient/paginatedresource.py b/examples/demos/colorpaletteclient/paginatedresource.py
new file mode 100644 (file)
index 0000000..b7f036c
--- /dev/null
@@ -0,0 +1,278 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import sys
+from dataclasses import dataclass
+from PySide6.QtCore import (QAbstractListModel, QByteArray,
+                            QUrlQuery, Property, Signal, Slot, Qt)
+from PySide6.QtQml import QmlAnonymous, QmlElement
+
+from abstractresource import AbstractResource
+
+
+QML_IMPORT_NAME = "ColorPalette"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+totalPagesField = "total_pages"
+currentPageField = "page"
+
+
+@dataclass
+class ColorUser:
+    id: int
+    email: str
+    avatar: str  # URL
+
+
+@QmlElement
+class ColorUserModel (QAbstractListModel):
+    IdRole = Qt.UserRole + 1
+    EmailRole = Qt.UserRole + 2
+    AvatarRole = Qt.UserRole + 3
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self._users = []
+
+    def clear(self):
+        self.set_data([])
+
+    def set_data(self, json_list):
+        if not self._users and not json_list:
+            return
+        self.beginResetModel()
+        self._users.clear()
+        for e in json_list:
+            self._users.append(ColorUser(int(e["id"]), e["email"], e["avatar"]))
+        self.endResetModel()
+
+    def roleNames(self):
+        roles = {
+            ColorUserModel.IdRole: QByteArray(b'id'),
+            ColorUserModel.EmailRole: QByteArray(b'email'),
+            ColorUserModel.AvatarRole: QByteArray(b'avatar')
+        }
+        return roles
+
+    def rowCount(self, index):
+        return len(self._users)
+
+    def data(self, index, role):
+        if index.isValid():
+            d = self._users[index.row()]
+            if role == ColorUserModel.IdRole:
+                return d.id
+            if role == ColorUserModel.EmailRole:
+                return d.email
+            if role == ColorUserModel.AvatarRole:
+                return d.avatar
+        return None
+
+    def avatarForEmail(self, email):
+        for e in self._users:
+            if e.email == email:
+                return e.avatar
+        return ""
+
+
+@dataclass
+class Color:
+    id: int
+    color: str
+    name: str
+    pantone_value: str
+
+
+@QmlElement
+class ColorModel (QAbstractListModel):
+    IdRole = Qt.UserRole + 1
+    ColorRole = Qt.UserRole + 2
+    NameRole = Qt.UserRole + 3
+    PantoneValueRole = Qt.UserRole + 4
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self._colors = []
+
+    def clear(self):
+        self.set_data([])
+
+    def set_data(self, json_list):
+        if not self._colors and not json_list:
+            return
+        self.beginResetModel()
+        self._colors.clear()
+        for e in json_list:
+            self._colors.append(Color(int(e["id"]), e["color"],
+                                      e["name"], e["pantone_value"]))
+        self.endResetModel()
+
+    def roleNames(self):
+        roles = {
+            ColorModel.IdRole: QByteArray(b'color_id'),
+            ColorModel.ColorRole: QByteArray(b'color'),
+            ColorModel.NameRole: QByteArray(b'name'),
+            ColorModel.PantoneValueRole: QByteArray(b'pantone_value')
+        }
+        return roles
+
+    def rowCount(self, index):
+        return len(self._colors)
+
+    def data(self, index, role):
+        if index.isValid():
+            d = self._colors[index.row()]
+            if role == ColorModel.IdRole:
+                return d.id
+            if role == ColorModel.ColorRole:
+                return d.color
+            if role == ColorModel.NameRole:
+                return d.name
+            if role == ColorModel.PantoneValueRole:
+                return d.pantone_value
+        return None
+
+
+@QmlAnonymous
+class PaginatedResource(AbstractResource):
+    """This class manages a simple paginated Crud resource,
+       where the resource is a paginated list of JSON items."""
+
+    dataUpdated = Signal()
+    pageUpdated = Signal()
+    pagesUpdated = Signal()
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        # The total number of pages as reported by the server responses
+        self.m_pages = 0
+        # The default page we request if the user hasn't set otherwise
+        self.m_currentPage = 1
+        self.m_path = ""
+
+    def _clearModel(self):
+        pass
+
+    def _populateModel(self, json_list):
+        pass
+
+    @Property(str)
+    def path(self):
+        return self.m_path
+
+    @path.setter
+    def path(self, p):
+        self.m_path = p
+
+    @Property(int, notify=pagesUpdated)
+    def pages(self):
+        return self.m_pages
+
+    @Property(int, notify=pageUpdated)
+    def page(self):
+        return self.m_currentPage
+
+    @page.setter
+    def page(self, page):
+        if self.m_currentPage == page or page < 1:
+            return
+        self.m_currentPage = page
+        self.pageUpdated.emit()
+        self.refreshCurrentPage()
+
+    @Slot()
+    def refreshCurrentPage(self):
+        query = QUrlQuery()
+        query.addQueryItem("page", str(self.m_currentPage))
+        request = self.m_api.createRequest(self.m_path, query)
+        self.m_manager.get(request, self, self.refreshCurrentPageReply)
+
+    def refreshCurrentPageReply(self, reply):
+        if not reply.isSuccess():
+            print("PaginatedResource: ", reply.errorString(), file=sys.stderr)
+        (json, error) = reply.readJson()
+        if json:
+            self.refreshRequestFinished(json)
+        else:
+            self.refreshRequestFailed()
+
+    def refreshRequestFinished(self, json):
+        json_object = json.object()
+        self._populateModel(json_object["data"])
+        self.m_pages = int(json_object[totalPagesField])
+        self.m_currentPage = int(json_object[currentPageField])
+        self.pageUpdated.emit()
+        self.pagesUpdated.emit()
+        self.dataUpdated.emit()
+
+    def refreshRequestFailed(self):
+        if self.m_currentPage != 1:
+            # A failed refresh. If we weren't on page 1, try that.
+            # Last resource on currentPage might have been deleted, causing a failure
+            self.setPage(1)
+        else:
+            # Refresh failed and we we're already on page 1 => clear data
+            self.m_pages = 0
+            self.pagesUpdated.emit()
+            self._clearModel()
+            self.dataUpdated.emit()
+
+    @Slot("QVariantMap", int)
+    def update(self, data, id):
+        request = self.m_api.createRequest(f"{self.m_path}/{id}")
+        self.m_manager.put(request, self, self.updateReply)
+
+    def updateReply(self, reply):
+        if reply.isSuccess():
+            self.refreshCurrentPage()
+
+    @Slot("QVariantMap")
+    def add(self, data):
+        request = self.m_api.createRequest(self.m_path)
+        self.m_manager.post(request, data, self, self.updateReply)
+
+    @Slot(int)
+    def remove(self, id):
+        request = self.m_api.createRequest(f"{self.m_path}/{id}")
+        self.m_manager.deleteResource(request, self, self.updateReply)
+
+
+@QmlElement
+class PaginatedColorUsersResource(PaginatedResource):
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.m_model = ColorUserModel(self)
+
+    @Property(ColorUserModel, constant=True)
+    def model(self):
+        return self.m_model
+
+    def _clearModel(self):
+        self.m_model.clear()
+
+    def _populateModel(self, json_list):
+        self.m_model.set_data(json_list)
+
+    @Slot(str, result=str)
+    def avatarForEmail(self, email):
+        return self.m_model.avatarForEmail(email)
+
+
+@QmlElement
+class PaginatedColorsResource(PaginatedResource):
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.m_model = ColorModel(self)
+
+    @Property(ColorModel, constant=True)
+    def model(self):
+        return self.m_model
+
+    def _clearModel(self):
+        self.m_model.clear()
+
+    def _populateModel(self, json_list):
+        self.m_model.set_data(json_list)
diff --git a/examples/demos/colorpaletteclient/rc_colorpaletteclient.py b/examples/demos/colorpaletteclient/rc_colorpaletteclient.py
new file mode 100644 (file)
index 0000000..74b3eaf
--- /dev/null
@@ -0,0 +1,1098 @@
+# Resource object code (Python 3)
+# Created by: object code
+# Created by: The Resource Compiler for Qt version 6.7.0
+# WARNING! All changes made in this file will be lost!
+
+from PySide6 import QtCore
+
+qt_resource_data = b"\
+\x00\x00\x00\xc0\
+<\
+svg width=\x2248\x22 h\
+eight=\x2248\x22 viewB\
+ox=\x220 0 48 48\x22 f\
+ill=\x22none\x22 xmlns\
+=\x22http://www.w3.\
+org/2000/svg\x22>\x0a<\
+path d=\x22M22.5 38\
+V25.5H10V22.5H22\
+.5V10H25.5V22.5H\
+38V25.5H25.5V38H\
+22.5Z\x22 fill=\x22#66\
+7085\x22/>\x0a</svg>\x0a\
+\x00\x00\x00\x94\
+<\
+svg width=\x2230\x22 h\
+eight=\x2230\x22 viewB\
+ox=\x220 0 30 30\x22 x\
+mlns=\x22http://www\
+.w3.org/2000/svg\
+\x22>\x0a<ellipse cx=\x22\
+15\x22 cy=\x2215\x22 rx=\x22\
+13\x22 ry=\x2213\x22 fill\
+=\x22black\x22/>\x0a</svg\
+>\x0a\x0a\
+\x00\x00\x0b\x93\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00d\x00\x00\x00H\x08\x06\x00\x00\x00\x00\x8cP\x19\
+\x00\x00\x01\x84iCCPICC prof\
+ile\x00\x00(\x91}\x91=H\xc3@\x1c\xc5_\
+S\xa5*-\x0ev\x90\xe2\x90\xa1:Y\x10\x15q\xd4\
+*\x14\xa1B\xa8\x15Zu0\xb9\xf4\x0b\x9a\x18\x92\x14\
+\x17G\xc1\xb5\xe0\xe0\xc7b\xd5\xc1\xc5YW\x07WA\
+\x10\xfc\x00quqRt\x91\x12\xff\x97\x14Z\xc4x\
+p\xdc\x8fw\xf7\x1ew\xef\x00\xa1Qe\x9a\xd55\x06\
+h\xbamfRI1\x97_\x11C\xaf\x08#\x82^\
+\xc4\x11\x93\x99e\xccJR\x1a\xbe\xe3\xeb\x1e\x01\xbe\xde\
+%x\x96\xff\xb9?GD-X\x0c\x08\x88\xc43\xcc\
+0m\xe2u\xe2\xa9M\xdb\xe0\xbcO\x1ceeY%\
+>'\x1e5\xe9\x82\xc4\x8f\x5cW<~\xe3\x5crY\
+\xe0\x99Q3\x9b\x99#\x8e\x12\x8b\xa5\x0eV:\x98\x95\
+M\x8dx\x928\xaej:\xe5\x0b9\x8fU\xce[\x9c\
+\xb5j\x8d\xb5\xee\xc9_\x18.\xe8\xcbK\x5c\xa79\x84\
+\x14\x16\xb0\x08\x09\x22\x14\xd4PA\x156\x12\xb4\xea\xa4\
+X\xc8\xd0~\xd2\xc7\x1fs\xfd\x12\xb9\x14rU\xc0\xc8\
+1\x8f\x0dh\x90]?\xf8\x1f\xfc\xee\xd6*N\x8c{\
+I\xe1$\xd0\xfd\xe28\x1f\xc3@h\x17h\xd6\x1d\xe7\
+\xfb\xd8q\x9a'@\xf0\x19\xb8\xd2\xdb\xfe\x8d\x060\xfd\
+Iz\xbd\xad\xc5\x8f\x80\xfem\xe0\xe2\xba\xad){\xc0\
+\xe5\x0e0\xf8d\xc8\xa6\xecJA\x9aB\xb1\x08\xbc\x9f\
+\xd17\xe5\x81\x81[\xa0o\xd5\xeb\xad\xb5\x8f\xd3\x07 \
+K]\xa5o\x80\x83C`\xa4D\xd9k>\xef\xee\xe9\
+\xec\xed\xdf3\xad\xfe~\x00a\xaer\xa0\xbc\xa9O\xc0\
+\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\
+\xa7\x93\x00\x00\x00\x09pHYs\x00\x00.#\x00\x00\
+.#\x01x\xa5?v\x00\x00\x00\x07tIME\x07\
+\xe7\x0c\x0d\x09$9Q3\xe6g\x00\x00\x00\x19tE\
+XtComment\x00Create\
+d with GIMPW\x81\x0e\x17\x00\
+\x00\x09kIDATx\xda\xed]ilT\xd7\x19\
+=\xe7\xbe\x99\xb1\xcd\x1aC\xc0\xac\xb6\xb1\x81\xda\x1eC\
+T\x11\x10\xa4i\x135\x91\x12E\xa4KT\x14\xda&\
+$]\x14W(\xa9\x02\x81\x006\x84Q\xf0B\x96\x06\
+*D\xd5\xf6\x17\x0a\xaa\xda\x84F)R\xc2\xa2$\x85\
+&M\xd3\x85%\xc2cV\x8f1aKR\xb0qX\
+\xec\x99y\xef~\xfdAAN\xeb\xfb\xbc\xf0f\xf0x\
+\xe6\xfe\x9b\xf9\xde\xdc\xef\xbe{\xde\xf9\xb6{\xef\x1b\xa2\
+\x87\xad\xbc\xf9\x85Rh{'\x80\xf1\xc8\xb4\x844\x81\
+\x08{\x04F\xa4\xfav\xa1\xbcA\xa8\xfc\xcc\xb4%\x12\
+\x10\xe8n\x01\x09\x9e\xa8-\xa3-;AL\xc8LY\
+\xe2\x01Q\xdd1\x03\x8e\xb3=\x03F\xf2\x9a\x91!e\
+\xc7\xd6\x06\x95\xa5w\x00\x92\x01\xe3f3$\x18y~\
+&\xad\xf8\xb6\x0c\x18\xfd\x80!e'\xd6\x06\x95\xed\xec\
+\x043\xd1\xd4MgH0\xf2\xfcL\xda\xf6\xf6\x0c\x18\
+\xfd\x80!\xa5\x8d5\xe5\x16\xb1#\x03F?`H0\
+R7SQ\xb6e\xc0\xe8\x07\x0c)\xfd\xa4\xa6\x5c\xd9\
+\xd8I`\xdcM}:D\x84\x8a\xed\x10DE\xc4\x01\
+\x00\x92>\x00\xd9\x02\xc9\x22\xc8t`\x88O\xd9\xfam\
+B\xdd\x0c0: \xd8\x01\xca\x87\x8e\xb6\x22>\xb2\xd1\
+\xa6s\xae\xfdB\xbc}\xd8\xd8\xc1q\x00\xf8\xe2\xece\
+\x7fN\xae?'\x00=&\xae\xd5d\x05N\x15p6\
+!w\x01\x18:\x10A\xf1\x11jB\x12i\x00\x90{\
+\x04\xd8t\x99\xf1\xdf5\x17\x85.\xf4\xe0W\x17\x00\x9c\
+\x05\xb0\xffz\xc2\xdaT\x93G\xe1\x0f5\xf4\xcfHN\
+\x19P&\xab\xbc\xa9\xc6\x01\xa0\x92\x10=\xb4A\xb8(\
+\x90\x13{m\xef\xb8\xd0\x15/\xfa\x9c|\xec\xa9\xac,\
+k\xecRB\x9e\x060r \x98\xac\xe4\x00B\x1c\x12\
+\xc5\xef5\x14T\x1eLD\xf7\xc1\xc6\xda\xafQ\xc9\xab\
+\x00\x8az9\x03\xbfQ>l\xe9J\xe4h\xf5\x14E\
+\x7f;\xe9>$\x09Z\xc2v4\xfe\xe0\xe1\xd2Ps\
+\xa2T4L\xae\xfc\xb04\xb2\xe6~K\xa9w (\
+\xe8\xf9\xd0\xe4\xf0\x81\x82\x95\xefu]\xad\xa8y\x087\
+!\x8cP\x09\x06\xe3\x1c\xfc\xbe\x1f%\x12\x8ck\xedP\
+\xf1\xaacZ\xe1'W\x1dU\x0a;\xf5\xc4Z*\xd9\
+P\x9f\xbflOw\xd7\x956U\x17(\x8d\x87I\x94\
+\x80\x9c\x00\x91\x5c\x90\x1a@\xab\x10'\xe8H\x03rr\
+\xde\x0c\x8f\x7f\xe6\xa4[?\x07\x0b\xaa\xde\x9bv\xbc\xfa\
+%\x11<\x9b\x01\xe4\xff\xd1\x88\x5c\xa4\xfd\xa2\xdb%e\
+\x91\xd5\xf9\x14\xff*\x80?\xa6\xea\xc4\xd6N)\x07\x05\
+\x80\x22$\xda\xb1\xa6<R\xf3{;v\xa9\xeapi\
+\xddyS\x9f1\xcb\xffK\xbf\x1d\x7f\x14\xe0\xd8T\x04\
+$a&K\x93\xbfj\x9e\x14\xea0\xc9o;V\xf7\
+U\xa5\xb2vQ\xf1\xa7\xec\xc18\x08\x0c\x03Qae\
+\x0d\xf9\xdb\xb4\xa3!\xa3\xf3>\x92\xbf\xec\x8ch\xbc\x91\
+\xaa\x0cI\x0c \xe4yZ\xd9\x9bL\xe2\xf2\xa6\xf5y\
+\xb6\x92\xcd\x10)\xea=\xf10U\xfc\xfe\xcd\x08\x85\x8c\
+c\x8f_\xb17^\x0dZ2\x80\xfc\xd7\x99\xebm\x0d\
+\x13\x17\xb7\x98\xf1\xbaRAJ\xf0\x06\x82\x85;\xca\x17\
+\xf8\x17\x99\xc4G\xa7\x87\x0e\x83\xf8G\x06\x90k\x13\xae\
+\xf5\x9fM\xb2\x92C+F\x8a\xc8\x93\x1e\xa8y\xa4\xac\
+!\x140\x9aL-[3N\xfd*\x1cq\xfa\xf8\x17\
+\xa3B\xdf\xe0\x07\x00\x8c\xf2\x80\x86\xb7I\x8eo6\x80\
+\xf7\xbb\x1c\x85e\xfd\x13Z\x0b:/\xc2i\xfc\x09\xc4\
+\xc7\xd7>Z\x1a\x7f7>\xa9\x16\xdf\x16G>7j\
+W\x14\x8a~\x04\xf0\xb6t\x93\x00@t\xd3C\x05\xce\
+\x89\x03&\xb1\x85\xbb\xbcrT\x8ab\x04$\x1e\xf5\x1f\
+\x08\xf8;\xda\x00\xder}\x12\xfd\xd6\x9b\x0d\x05\xcb_\
+\xedI\xef\xf5\x85\x95\xdb\x00ls\xad\x104U\xcf!\
+0\xa5_\x9b,R\xed\x0b1\xa4]\xae\xb8\xd3\xbb\xc8\
+\x9a\xb3\x8d~d\xea\x92\xf3\x00\x1b\xd3\xde\x87h\xc8'\
+&\xd9\xf4OC\xa3\x05\xe2\xd9\x13%\x22s\xdc\xb2R\
+\x11}4\xed\x01\x11\x91SFY{\xa0\x94\xa0\xf2\x8e\
+\x8d\xcc\x9bu\xa8\xd6\x5c\xe5U\xea\xb3\xb4\x07\xc4\xd2f\
+@\xe8\xa0\xd0[\xf4\xc1+\x01=\xc9\xa8O\xe4\x5c\xda\
+GY\x9a\xbe\xd3\xc6\xf9\xf3#\x0f\x8e\xe7\x9c\xcc\x07`\
+\xa8\x97\xa9\xcf:\xe7\x87t\xf4\xbc`\xa4\xfaz\xfe#\
+\xd4o\x1d,z\xee\x83.\x93\xd7\xc6\xba\xef\x0a\x9d\xd9\
+\xdd\xf8\xcb\xa9^\xd72\xbd\x8f\xb2\x02h5\x82e\xcb\
+\x08\xafW\xc6\x85j\x84\x0b\x83Z\xbf\x5cB\x97\xb9$\
+\xe7v\x8a]\xcf\x02\xf8\xa0\xeb~\xf5\xbd$\x17vc\
+\x9fS\xc0\x87\xd8\xd1K.\xda\x02\xdeW\x05d\x88Q\
+\x9dO\xda\xd2\xdc\x87\x88\x040\xbc\xc3E\xec\xf7\x1c\x0f\
+ \xdbl?}\x97\xd3\x1a\x10\x01\xe5\x92\xdd\xe6\x96\x83\
+x\xbe\x06G*\xa3\xd9\xb5\xe3\x8e\xa49C2\xad_\
+\x01B\x08\x87\xf8\xdc\xfaL\x80\x17\x14\x89\x1bo.\xa0\
+\xac4g\x08\x19s\xb3\xe9.\x93\xd7\xf7\xca\x806\xfb\
+,mv\xf8\xe9\x93\xa9kk\xa8\x99A\xaa\xc3\xf3D\
+JY_\x98}\x9a=,\xed\x01\xf1Y\xd6\xad.6\
+\xad\xd5\xfb[\xd0-.\xa3\xb9%\xc3\x10\xcaD\x17\xf1\
+Y\xaf\xf5\xd96O\x9a\xf1\xd7y\x99(\xcb\x11\xe3\xd1\
+ij\xe7\x90\xb7a\xb68\x83\x06\xc7\x8d\xd5e\x0ao\
+\xcd\x00\x224n\xde\x0e\x0c\xca;\x04 \xe6]T\x87\
+S{\xc7\xae>o\x1e\x8a\x1e\x9f\xf6\x80\x08\xcd\x15\xdd\
+\xbd\xe3*\xae@\xe4\x80\x87q\xf6>\x90]\x87\xd2\x12\
+R\x04K\xd3\x1e\x10\x12\xe5\x85\xc7C\xd9.\x80\xed\xf0\
+L\x97\xa6qgIY\xf3\xa0\xd1\x00\x8a3&K$\
+?K0\xd5\x05\xb1\xbfz\xe4@lZx\xc7\x18_\
+\x89=K\x80\x9c\xbe\xa3-z`\x00\x02\xfa\x03\xf0\x1b\
+\xd7\x11\xa2\xf6\xa7\xbb\xa9e\xbf\x07\xd1\xdc\xbb\x07\x0a*\
+\xf7\xbb\xc8\xef\xe8\x9e\xcdb\xb9\x00~e\x80\x00\x02\x80\
+\xf8\x8eI\xd48eCT,\xeb\x85\x1b\x84#F\x91\
+\x8d&\xffQ&\xa1\x80\x80\xdd\x9e\xed\xd0B\xbf\x8b\xe9\
+m\x1b0\x80\x88\xe0\xbe\x92\xb3uF\xe7\x1e\x9e\xb4\xe2\
+5\x81\xbc\xd2wk\xc5\x17\xc2\xc5\xab\xde2\xdeTS\
+`.DJ\xba\xbfy\x0e3\x97dxn\xe00\x04\
+P\xbev\xbd\xd8\xed\x82\xecI\xa3\x96\x8b\xc8\x22\x11\xb9\
+\xd8\x0b\xea}\x0e\x8d\x9f7\x14U=g\xbc$\x14R\
+\xa0<\xdeC\xb3g<\xec\xaa\xc4\xb7\x0f\x80=P\x00\
+\x01\xc0\x87\xbf\xd2\xbc\xc6\xb8\x01a/+\xe2\x0d\xc5+\
+\xd7S\x10\xa4\xe23B\xd9!W7%H\xa7\xc4O\
+@i\x01e\x1b\xa1\x9f\xd4\xa2f\x86'Wmp\xd3\
+\x1a|\xd4?\x1f\x90\xb9=\xb3\xac,7\xb2\xb8x\xd9\
+\x1e\x00\x95\xc0\x97\xcb=\x22\x22\x00\xa2\x22\xb8\xe8eN\
+u}L\x09=c(\xfcC\xb8\xb8\xf2\xfb\xbd\xb0u\
+\xaa\xe4t].cz\x88\x95\x95\xa3y>v\xa9~\
+Z\xb4\x0d\xae\x1b\xef:\xf9\x8e\xc8\xea|K\x05v\x8b\
+`R\xcfL\x1f:Z\xb3\xe3#\xcf\xb8\x1cB\x9ds\
+rQN\x8b3b\x8c\xdf\x1ed\xfb%\xda\x11\x8d\xc5\
+\xda\x01\xc4\x0en\x81]\xbe\xc0\xbf\x0b\xc07\xbc\xab<\
+$\xe1\xd0\xa7\x08\x167\x14W\xadK4\xd5g\x9c\x09\
+\x0d\x8av\xf8\xdf\x050\xa7w&B\xcf;P\xb4\xea\
+\x8f}\xd1\x19l\xaa\xddJ\xc8\xb7\xbc\x04$\xf1\xc7\xa1\
+\x89\x9a\xe9\xc7\xea\x16&RGis\xcd\xd8h\xbbo\
+ko\xc1\x00\x00\x07j\xfe\x0d\xa4*\x17\xbd\xbe\x97d\
+,\xe1\xe6hKo\x9c\x16\xa9]7\xbd\xf1\xa5\xd1^\
+w^r\xaav\xa4%\xb2\x1d\xe4\xbd}\x8b\xd0\xf1`\
+\xb0y\xcd7\xfb6{LI@\xaeE4Ok+\
+\xf6Q0R\xbdp\xc6\x99\x90gU\xd8\xc3\xe3W\xb4\
+@X\x7f\x03]\x04 \xd6\xe6\xe9\xc7\xeb\xee\xef\xf5/\
+\xb5\x8e\xa6\x96S7\xb7\x16@\xb6\x13|\x1fb}\xe4\
+\x14u\x1c9\xc8\x909b\x91y\x16\xb8\xc5\xb8\xe7\xb1\
+\xbc\xa9&\x0f\x90\x8f\x01\x8e\xe9{.\x8bvM\xbe\xae\
+\xb4\xf3\xfa\xf9\x9c\xd1\xbb\xcf\x8c\xab\xe8\xd2\xd1\xdf\xbd\xeb\
+n\xdf\xbf'\xdeWH\x89\xcf\x86\xa5*\xbc\xdc\xcd\x9f\
+\xbc79t?\x92\x8b\xa04\x0bp\x9a\x1am\xa2\xd0\
+\x01R(\xcc!0N(A\x08\xe6\x87\x8b\xaa\x8c\xb5\
+\xab\xe0\xf1\xea\xc7(\xdc\xe4\xd1\x88.\x028,\x82\x93\
+\x10}\x89\xca\x22\x94\xce\x15\x07\x93\x14Y(\xc0\xe0\xc4\
+LC\x7f\x01\xa4g\xcf\xf0\xbf\xe2g.\xdcs\xe4\xce\
+\x17\xbb\xb4\xdb3\xf6<\xe1\xef\xc8\xcd\xdfN\xf2\x1e\xa4\
+hKJ\x94\xe5\xe1pg\xfa\xf2\x86/0&\x9a\xb7\
+\xff6\xaeb\xbeE\x90\xe4g\xd7)\xe9\xd4=\xe1\x88\
+\x85\xba\x92\xe3\xa1B\x93\xbc\xbety=\xc8\xd5\x19@\
+\x92\xd7\x86\xfa$\xb0\xd6\x95G\xed\xb1_\x03\x08\xa7\xa2\
+\xb9\x22\xb8,\x05\xb7\x92\xca\xbci\xcd\xb5\x0f\x98\xa4\x0d\
+\xc1P\x8b\x80U\xa9\xf4\x12\x1a\x11\x11\xa5di\xb8\xa8\
+\xf2\xe5T\xdc\xdb\xabD\xcb\xcb3\xf6<\xd1\xe5Z\xc6\
+\xe4c\xb5\xa3D\xcb\x18\x08/\xa5\x06\x18\xd0\xb4\xac\xa5\
+\xf5\x85+_\x01\x12\xfc6\xa0DVKb\xb9\x05k\
+\x00,\xbf\xf6\xc5\xacS\xb5#\xdb\xa3\xfaY\x81\xfc \
+U\xdeU/\x22\x02\xc5%\xe1\xc2\x15\xebnvb\xe8\
+Ek\xd5\x96\xf5\xf5\xac\x98\x16[\xe11!*\x00\x19\
+\x9e:>C\x1c\x82\xcb\xc2EU\xbf\xe8\xfc}\xaa2\
+\x04\x00ri\xdb[c\x8a\xa3\xc9\xd4zC\xe9\xd55\
+\x15.\x0dwQ\x05Oe@@2\xe5\xb6\xf9\x08\xc4\
+!\xb9,\x5c\xd4\xf5\x92DJ\x03\x92r`\xb80#\
+U\xf3\x90\xd4\x05\x03\xe2(\xa8%\xdd-\xd6e\x18\x92\
+4f`I}q\xe5\xfa\x81\x96\xa9\xa7(3\xb0\xa4\
+\xa1x\xe5\xfa\x9e\x5c\xef\x03\xe4q\xe9\xc1\x9f\x83eZ\
+\x1f\x03\x0f\x9b-\xf5S\xcd{\xc8\xfe\xb7\xfd\x07:\xcc\
+\xccF\x8ay\xc7t\x00\x00\x00\x00IEND\xaeB\
+`\x82\
+\x00\x00\x02\xed\
+<\
+svg width=\x2248\x22 h\
+eight=\x2248\x22 viewB\
+ox=\x220 0 48 48\x22 f\
+ill=\x22none\x22 xmlns\
+=\x22http://www.w3.\
+org/2000/svg\x22>\x0a<\
+path d=\x22M24 40C1\
+9.5667 40 15.791\
+7 38.4417 12.675\
+ 35.325C9.55833 \
+32.2083 8 28.433\
+3 8 24C8 19.5667\
+ 9.55833 15.7917\
+ 12.675 12.675C1\
+5.7917 9.55833 1\
+9.5667 8 24 8C26\
+.8333 8 29.3167 \
+8.575 31.45 9.72\
+5C33.5833 10.875\
+ 35.4333 12.45 3\
+7 14.45V8H40V20.\
+7H27.3V17.7H35.7\
+C34.4333 15.7 32\
+.8167 14.0833 30\
+.85 12.85C28.883\
+3 11.6167 26.6 1\
+1 24 11C20.3667 \
+11 17.2917 12.25\
+83 14.775 14.775\
+C12.2583 17.2917\
+ 11 20.3667 11 2\
+4C11 27.6333 12.\
+2583 30.7083 14.\
+775 33.225C17.29\
+17 35.7417 20.36\
+67 37 24 37C26.7\
+667 37 29.3 36.2\
+083 31.6 34.625C\
+33.9 33.0417 35.\
+5 30.95 36.4 28.\
+35H39.5C38.5333 \
+31.85 36.6167 34\
+.6667 33.75 36.8\
+C30.8833 38.9333\
+ 27.6333 40 24 4\
+0Z\x22 fill=\x22#66708\
+5\x22/>\x0a</svg>\x0a\
+\x00\x00\x01\xb3\
+<\
+svg width=\x2248\x22 h\
+eight=\x2248\x22 viewB\
+ox=\x220 0 48 48\x22 f\
+ill=\x22none\x22 xmlns\
+=\x22http://www.w3.\
+org/2000/svg\x22>\x0a<\
+path d=\x22M13.05 4\
+2C12.225 42 11.5\
+187 41.7062 10.9\
+313 41.1188C10.3\
+438 40.5312 10.0\
+5 39.825 10.05 3\
+9V10.5H8V7.5H17.\
+4V6H30.6V7.5H40V\
+10.5H37.95V39C37\
+.95 39.8 37.65 4\
+0.5 37.05 41.1C3\
+6.45 41.7 35.75 \
+42 34.95 42H13.0\
+5ZM34.95 10.5H13\
+.05V39H34.95V10.\
+5ZM18.35 34.7H21\
+.35V14.75H18.35V\
+34.7ZM26.65 34.7\
+H29.65V14.75H26.\
+65V34.7Z\x22 fill=\x22\
+#667085\x22/>\x0a</svg\
+>\x0a\
+\x00\x00\x01\xf7\
+<\
+svg width=\x2248\x22 h\
+eight=\x2248\x22 viewB\
+ox=\x220 0 48 48\x22 f\
+ill=\x22none\x22 xmlns\
+=\x22http://www.w3.\
+org/2000/svg\x22>\x0a<\
+path d=\x22M9 39H11\
+.2L33.35 16.85L3\
+1.15 14.65L9 36.\
+8V39ZM39.7 14.7L\
+33.3 8.29998L35.\
+4 6.19998C35.966\
+7 5.63331 36.666\
+7 5.34998 37.5 5\
+.34998C38.3333 5\
+.34998 39.0333 5\
+.63331 39.6 6.19\
+998L41.8 8.39998\
+C42.3667 8.96664\
+ 42.65 9.66664 4\
+2.65 10.5C42.65 \
+11.3333 42.3667 \
+12.0333 41.8 12.\
+6L39.7 14.7ZM37.\
+6 16.8L12.4 42H6\
+V35.6L31.2 10.4L\
+37.6 16.8ZM32.25\
+ 15.75L31.15 14.\
+65L33.35 16.85L3\
+2.25 15.75Z\x22 fil\
+l=\x22#667085\x22/>\x0a</\
+svg>\x0a\x0a\
+\x00\x00\x1a\x93\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00J\x00\x00\x00H\x08\x06\x00\x00\x00Q\x18cz\
+\x00\x00\x01\x85iCCPICC prof\
+ile\x00\x00(\x91}\x91=H\xc3@\x18\x86\xdf\
+\xa6\x8a\x22-\x0ev\x10q\xc8P\x1d\xa4\x05Q\x11G\
+\xadB\x11*\x84Z\xa1U\x07\x93K\xff\xa0IC\x92\
+\xe2\xe2(\xb8\x16\x1c\xfcY\xac:\xb88\xeb\xea\xe0*\
+\x08\x82? \xae.N\x8a.R\xe2wI\xa1E\x8c\
+w\x1c\xf7\xf0\xde\xf7\xbe\xdc}\x07\x08\x8d\x0a\xd3\xac\xae\
+q@\xd3m3\x9dL\x88\xd9\xdc\xaa\xd8\xf3\x8a\x10\xc2\
+4\xc7\x10\x93\x99e\xccIR\x0a\xbe\xe3\xeb\x1e\x01\xbe\
+\xdf\xc5y\x96\x7f\xdd\x9f#\xac\xe6-\x06\x04D\xe2Y\
+f\x986\xf1\x06\xf1\xf4\xa6mp\xde'\x8e\xb0\x92\xac\
+\x12\x9f\x13\xc7L\xba \xf1#\xd7\x15\x8f\xdf8\x17]\
+\x16xf\xc4\xcc\xa4\xe7\x89#\xc4b\xb1\x83\x95\x0ef\
+%S#\x9e\x22\x8e\xaa\x9aN\xf9B\xd6c\x95\xf3\x16\
+g\xadRc\xad{\xf2\x17\x86\xf2\xfa\xca2\xd7i\x0d\
+#\x89E,A\x82\x08\x055\x94Q\x81\x8d8\xed:\
+)\x16\xd2t\x9e\xf0\xf1\x0f\xb9~\x89\x5c\x0a\xb9\xca`\
+\xe4X@\x15\x1ad\xd7\x0f\xfe\x07\xbf{k\x15&'\
+\xbc\xa4P\x02\xe8~q\x9c\x8f\x11\xa0g\x17h\xd6\x1d\
+\xe7\xfb\xd8q\x9a'@\xf0\x19\xb8\xd2\xdb\xfej\x03\x98\
+\xf9$\xbd\xde\xd6\xa2G@\xff6pq\xdd\xd6\x94=\
+\xe0r\x07\x18|2dSv\xa5 -\xa1P\x00\xde\
+\xcf\xe8\x9br\xc0\xc0-\xd0\xb7\xe6\xf5\xadu\x8e\xd3\x07\
+ C\xbdJ\xdd\x00\x07\x87\xc0h\x91\xb2\xd7}\xde\xdd\
+\xdb\xd9\xb7\x7fkZ\xfd\xfb\x01\xa7vr\xbc\xf6x\x14\
+.\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\
+\xbd\xa7\x93\x00\x00\x00\x09pHYs\x00\x00.#\x00\
+\x00.#\x01x\xa5?v\x00\x00\x00\x07tIME\
+\x07\xe7\x0c\x0d\x0d+\x19\xea\xccr\xbc\x00\x00\x00\x19t\
+EXtComment\x00Creat\
+ed with GIMPW\x81\x0e\x17\
+\x00\x00\x18jIDATx\xda\xed[y`T\xd5\
+\xd5\xff\xdd\xfb\xde\xac\x99}\xb2/da\x93E@P\
+\xb1\xdaZZ\xfd\x94-\xc8\xe2\x04\x14\xb7JK\xe5\xf3\
+\x0b&\x80\x88\xd5\xb6Q\x8b~\x22\x90\x80b-\xa2b\
+QI\x18\x11H \x91\x8a\x15k\xddQPY\x0ck\
+\x12\xb2'\x93\x99\xc9\xccd\x96\xf7\xde\xbd\xdf\x1f\x81@\
+\x08\x89Qh\xc1\xaf\x9c?g\xee\xbcw\xde\xef\x9d\xfb\
+;\xe7\xfc\xce\x1d\xe0\x92]\xb2Kv\xc9.Y\xaf\xcd\
+\x91\xb7O\xedpl\x10.6\xbf\xc8\xc5\xe2\xc8\xf4\xe7\
+\xf8H@~\x82s\x0c\x03\xe1!\x0a\xfa1\x04\xe9\x0f\
+\x85st\x15\x97\x80\x02\xe0X\xe2\x8f\xa7:\xed\xef\x08\
+\xf8o8\xa0=\xe3\xebVp\xaca\xb2\xb8\xd89\x8f\
+\xb4\xfcG\x02\xe5\xd8\xc0\x05\xda \xfd\x0f\x07\xfd=\x01\
+\xb7\xf7\xec%\xa9\x00g\x8f\x17e\xab_\xf9\x8f\x02j\
+\xc6Jy\x02'\xfc\x7f\x01\x0c\xfd>\xbf\xe3\xe0\xdf\x10\
+\x8aYE\xf7\xab?\xff\x7f\x0d\xd4\xa4\xa7\x03\x89:\xbd\
+\xfae\x007\x9f\xcbu8\xe7\xaf\x8bT\xf5\xc8\x1b\xff\
+C*\xff_\x015\xe9in\xd4F\xc9\x8f\x10\x86\x5c\
+\x10\xa8\xbb[\xa7\x84$\xb8\x0f\xd6B\xd0\xa9aJ\x8d\
+\x86\xa0V\xf5t\xd9V\x0e\xb6\xbc\xd1\xa5^\xbc3\x8f\
+\xc8?z\xa0\xb2V\x86o#Dx\x0e\xe0\xb6n#\
+Da\xf0V6\xc1_\xed\x02g\x1c\x00@U\x14\xa6\
+\x94\x18\x18R\xec \x84\xf4\xc8_DQ\xe6\x15>\xa0\
+\xd9\xf4\xa3\x04\xea\xd6\x95\xd2\xcfD\x82\xa5\x1c\xb8\xba\x87\
+-\x84`S+\xdc\x07\xeb\xc0d\xe5\xackD\xad\x1a\
+\x96~q\xd0E\x9b\xbekC~\xaa\x12Tw\xbf\xf6\
+\xdf\xa4\xfcG\x01\xd4\xac5\xdc\xe6o\x93\x0a@\xc8\x9d\
+=\xad\x0b{\xdb\xe0>T\x0f\xc9\x1f\xec\xd5u5\x96\
+(\xd8.K\x84\xa8U\x7f\x17\xe1\xbf\xc0\x15\xd5S\xce\
+\x1cRuQ\x025s%7)T\x9e\xc3\x81\x05\xe0\
+\x88\xee\x96\x87\x22\x12Z+\x9b\xe1\xaf\xf9ae\x911\
+\xd9\x0eC\xb2\x1d\xa2\xb6g\xfe\x22\x9c,PY\x847\
+\xd6\xddE\x02\x17\x0dP\x8e\x15\xd2X\x22`\x09\xe1\xb8\
+\xbc\xdb7-3\xf8j\x5ch\xadl\xea\xe0\xa1\x1fj\
+\x82F\x05sZ,\xa2\xe2-=?\x01A9!\xe4\
+\xd1\xc2\xfb\xc57/8P\xb3\xd7*s\xbd>\xb6\xa2\
+\xa75A\x97\x0f\xde\xa3\x8d\x90\x02\xa1\xf3\xba\xcdU\x06\
+-,\x19q\xd0\xda\x0c=p=`\x8c\xa2\x8b^\xfc\
+\x95\xf0\xf4\xb9\xdc\x8b\x9e\xab\xb3\xdc\xef\xbf\x22%^\x80\
+^wv\xcc\x99\xac\xa0\xad\xa9\xf5\xbc\x83\x04\x00\x92?\
+\x04_\x8d\x0b\xbc\x9bD\xa0\xd3\x12$\xc4P\xc0\xe7\x1b\
+p\xae\xf7\x12\xcf\xf5\x02\xfb\xfe~\x14q\xe96)\xed\
+\x8ax\xc1\xa0\x17\xa9\xdb\xc3 \x9d\xe67\x15\x05\xd8/\
+K\x82!\xc1\x0a\xcf\x91zDZ\x83\xe7'\x9a\xa2\xb4\
+\xb0\xf4\x8b\x87\xd6\x1a\xd5\xf5\xa1\x04\xc0f\xa6\xa0R\x84\
+\x1d\xfe\xb0\x96\xb9\xaa[\xc9\x05\x07\x0a h\xa8p\xab\
+\x9a\xab[\xa5\xb8t\x0bRG$ (\x11\xea\xf2\xb0\
+\xceY\xcb\xacG\xdc\xc8\x0c\x04\xea=\xf0\x1ci\x00\x93\
+~X\x8dHE\x0aC\xb2\x1d\xa6\x94h\x10\x81v\xe1\
+\x11\xb3\x91\xc2\xa8\xe7J\xcd\xfe&\xd4|\xdbDeI\
+\x11A\x08\xbf\xe0@q\xc2\x09\x01\x81\x22+\xaa\xdaC\
+.\xb8j[\x91:4NJ\xedkS\xb5x\x19|\
+\x81\xce>F\xc5[\xa0\xb5F\xc1_\xebFke\xd3\
+\xf7\xcbxIv\x18S\xa3!\xa8\xbb\xba\x1d\xa5#\xb0\
+[(\x9a\x8e\xb5(\x07\xf6\xd4\x139$\xd3\x19\xd7\xd7\
+`o\xa5\x11{+M\xb8\x08\x22\xea\x8c\xfa( \xe1\
+\xe0\xa7\xd5\xaa\xe3\x07\x9a\xe4!?M\x859^+6\
+63Dd\xde9k\xa5\xc7\x22*\xc1\x0a\xf7\xc1:\
+\x84Z|=^Sm\xd2\xc1\xda/\x01j\x93\xae\xeb\
+\x03\x88@\x9cM\x80\x1c\x0c\xc9{\xdf\xad\x15\xbc\x8d~\
+\xe1Z\xa1\x12aQ\xc4\xc8\x0c/v~c\x07\x01\xf8\
+E\x00\x14\xc5\xd9\xfc\x08\xb6\x86\xc5]\xa5\x07\x11\x93j\
+\x8e\xf4\x1b\x95\xa8\x0eC\x84\xdb\xcbp:\xef\x8aZ\x15\
+b\x86\xf5A\xd8\xdb\x86\x96\xf2Z\xc8m\xe1\xceWV\
+\x09\xb0\x0dL\x82\xd6n\xe8\xd2\xc6\x10\x02D[)t\
+*\x8e\xf2\x8f\xab\xe4\xe6*\x8fh\x89mC\xd2\xc00\
+\xa6T\xee\xc7\xb2\xc8O\xb1pmR\xfbZ\x8e\x8b/\
+\xa2\xce\xb4\xa6J\xaf\xba\xb9\xaa\x15\xa9\xc3b\x918(\
+\x16\xfe \xe0\xf6v\xe5\xaf\x84\xab\xfa\xc1_\xe3\x82\xb7\
+\xaa\x19\x5cV`H\xb1\xc3\x9c\x1a\x03Bi\xd7t\xaf\
+\xa7\xb0Y\x08\xea\xca]\xf8\xfa\xabz\xc8\x92\x22\x02\xc0\
+\xe8[\x8e\xe2\xc0G\x09x04\xaes\xe6\x05\xbb\xf8\
+\x81:\xd9\xd3U|\xd5\x80\xfa\xc3nd\x8cL@j\
+\x8a\x19\xcdn\x86@\x90wbbC\xb2\x1d\xfa8\x0b\
+\x00\x0e\xaa\xea\xea\x9aVC\x10k\xa3\x084\x07\xf0\xd9\
+\xa6*\x84\xdb\xa4N\xdf\xbf\xf3\xca`0\x99\x9e\xa5\x96\
+\x12\xd8\x85\x07J\x11\x9f\xe7\x824\x86\x00\xa9\xdf\xb54\
+\x14\x88`\xff\x07\x95\x88\xb2j1\xf8\xfa4XLj\
+4\xba\x14\x9c\x9e\x00\xa9J8k\xba\xb7[(\x88,\
+\xe1\xdb\x0f\xea\xe0\xaa\xf6vS\xb3\x9d\xb5,t\x83\x93\
+\xd7.\x8a\x16\xe6g\xd9\x87b\xd4\x11\xfaN\xc8\x13\x18\
+\xce\xe5\xde\xbf\xbc\xf8~v\xa4\x0f\x8bE\x88\x8b\xf0\xb6\
+v\xae\xbf\x00\x80\x12\xc0j\xa6\xd0\xab9\xaa\xbei@\
+Mys\xaf\xdb\x1f\x22P\xe8l\x86]A\x8f\xe7\x96\
+\x0f\x0bG\xd6^P\xa0&M\xcd\xb9\x8ed\xdc`\xd3\
+\xa5\x8e]\xc6\x81\xferH\x82\xf7h\x03\xda\x1a\xbd\xbd\
+w\x80\x12\xf4\xbd2\x11q\x196x\xfd\x1c\xa1\x08\xc0\
+\x19\xa0\xd5\x00V\x13Ec\x85\x1b\xc7\xf6\xd4A\x0a\xf6\
+\xbe\xee\xd2Z\xa3`\x1d\x98t\xa2q\xe6\xfb\xa5\xa3\xa5\
+\x8fJ\xc7w\x86J\xde,(\xfb\xc1\xfd\xe5\xb9\x005\
+h\xf4X_\xca\x15\xe3WP\x8dqTDj\xaf\xc2\
+\xf51&hLzH\xbe\x10\x98\xa4\xf4\x82\xc0\x80\x96\
+\x1a\x1f\x9a+\xbd0[T\xb0YE\x18t\x80\xec\x0f\
+\xe2\xdb\x0f\xabPw\xd0\x05v\x22J\x09%P\xa9E\
+0\x85u_F\xf4O\x809#\x0eTl\x7f4\x83\
+\x9e\xc6\x98-\xa6\x18_\xf9\xae%\xe5\xe5\x1fF.\xd8\
+\xd6\xbb\xf9\xd7\xdf\xbe\x9c:<a\xa6!\xce\xa8nv\
+3\x84#\xbc\x03\x80@\x83\x1b\xde\x8a&(!\xa9\xf7\
+\x0e\x11\x02\x10t\xd9b\xa2\x8a\x22q`4\x98\xc2P\
+}\xa0\xf9\x8cj]\x801\xc5\x0ec\xb2\xbd\xa3Z\xd7\
+\xaa\x09l\x16\x8a\xb0'\xc0\x8f|Q\xf7\xca\xf6\xd5\x03\
+f\xfd[\x9a\xe2\x89Y\xb9\x99\x9c\xf3.\xc0\xfaZB\
+d\xef\xcec\xea\x8a]\xc7\x11mP\x10k\xa3\x10\x84\
+\xf6W\x10\x15oE\xdc\x88t\x18\x12\xad=\xcb\xb9g\
+d\xc83A\x8a\xefgCB\x7f\x1b\xd4:\xb1\xcb\xab\
+5&\xd9\x10\x7fu_\x98Rc@\x04\x0a\x81\x021\
+V\x0a\xabNa\x15_TG\xbe\xdaq\x94\xfb\x5cm\
+g\xa7\x8e\xdbr\xc7\x8e\x1a5[u~\xb3\x1e'\xfa\
+\xcc\xacy\xaf\xdd2#\xf7\x85-\x85\xf9\x1f\x9c\xf6`\
+\x84\x10\x82\xfa#n4W\xb5\xca\xf1\xfd\xedH\x19\x1c\
+#\xb6I\x14\xeeV\x06A\xab\x82u@\x22\x8c)v\
+\xb8\x0f7 \xe4\xf2\xf5\xfa\x96\xf6d#\x0cV\x1d\xa8\
+H\xc1\x15\x8eHPF\x9b'\xdc\xa1x\x9a\xd3c\xa1\
+1\xeb;\xd6[M\x14\xe6(\xa0j_#\xaf\xf9\xb6\
+\x99&\x98\xfcj\xa3VDk[g,&e\xcd\xbf\
+^\x01\xbf\x1b2w~\xf1\xc5j\xe9\xbcr\xd4\xc1\xfd\
+\x1f\xef\x1b\xf3\xd3a%\x9e\x88\xe6\xa6\x81\x83G\xcfM\
+\xed{\xe5gG\xcb?\xf3\xa5\x0c\xb9o2\x01\x19\x01\
+\x00\x8cq\xda\xda\x14\xa0\xcdU^\x18\xcdj%!Y\
+G\x15\x05\x88H\x00U\x89\x88\x8a3C\x15\xa5\x85\xe4\
+\x0bv\xf0NO\x16\xdb\xc7\x02A-\x00\x1c\x08\xfa\x22\
+\xa8-w!\x12a\xb0\x0dJ\x82%=\xb6C\x16\xd6\
+k\x09\xe2\xec\x02B\xcd\xbe\xc8\xde\x7fT\xb0`u\xb3\
+@\xa1 \xff\xb7\xfbP^mD\x83[\xfb\xe5\xf1\x03\
+/\x14\xdf2c^J\xff!\xa3W3\x10\xbdMC\
+\xff\xe0\x5c\xbf\xfc\xc0\x0f\xe6\xa8\x89\x8e\xdc$\x86\xb0R\
+\xea|\xbe\xbe\xbb\x1f\x8d\x9d\x91\x93&*4\x1bP\x94\
+\x16vW\x02 \xdcq\xd6&6Z\x8b\x81\xa3\x93!\
+\x1a\xf4\x9d\xea%\xce\x18\x02u\x1ex\x8e5v\xab%\
+\x01@\x9f\xa1\xb1\xa0\x94\xa0j\x7f\xbb*jL\xb6\xc1\
+\xd4'\x16Dlg\x0c\x81\x02q\xd1\x02 EP\xfe\
+Q5<\x0d~P\x91\xe1\x09\xe1\x1d\xbc-\x0fDs\
+\xa2\x1d\x07\x8e\x1bA\x10*\xb2\x08\xeb?\x07H\x7fY\
+\xc6c\xdb\xdf*\xa8\xeb\xee\x9e\x93'\xe7X\x14\x9d \
+\x96\xac_\xd6\xdc#Pcg\xe4\xa4\x89\x8c\xe4\x82\x12\
+\xf7\xd6\xf5\xcb\x1e\xebI\xa2\x980}\xc1P\x9f\xf2_\
+\xaf\xcb<nX\x8f\xf5R\x7f;\xd2\x87\xc7#\xa4P\
+\xb4x\x19\xd8\x89`\x92\xc32|UM\xdd\xea\xe7\xa2\
+F\x80\x1cV\xa0\x8b5\xc3\xd6/\x1e\xf4\x84j@\x08\
+`5R\x18u\x1c\x87v\xd5\xa0\xf1\xa8\x1b\x9c\x03\xa3\
+\xc6\x1d\x83\x1c\x11 \xbc'\xe2+\x16\x0f\xe5\x04\x05\xab\
+H\xcd\xa1(\xf1ow\x96\x16\xae\xf8\xb4;\x1f\x07;\
+\x1c\xea\x0c\xd2'\x87\x83\xa5\x12\xae<\xbd\xd5\xb9\xb2\xaa\
+\x0bP\xe3o\x9f\x9f\x0a\xa6\x5c_ZX\xb0\xeeTd\
+-\xbc\x1a\x90\x9e\x86\xa0\xfcik\xe1\xcaw;\xed\xf1\
+I\x0b\x8d\x8aV\x9aJ\xb4\xd8\xe1\x0a\xdc\xb3\x98\x80\xdf\
+\xfd\x9dd\xa8\x11\x91<(\x06\xc9\x83b\xe0\xf5sx\
+|\xa7\xb6\x9e\x1c\x8c\xa0yo\x15\xa4@\xb8\x8b8g\
+\xed\x1f\x0f\x8d\xe5\x948g\xd4S\xd8\xad\x04\xf5\x87[\
+plw\x1d\xe4\xc8\xa9\x88\xec{E#*\xf7FC\
+\x96\xe8\x19\x09\x82\xbd\xa4a\x7f]`R\xd3\x89\x08y\
+\xb6\x14\x17\xbf\xdc\x89('d\xe5\xdeH\x81\xf9\x0cX\
+\xb6mC\xfe\x8eS\x810\x7f\xaa:\x12z\x7f\xd3\xa6\
+U\xae\x8e\x88\x1a\x9f\x95\x9bE9\xee\x0c3e\xde;\
+\x1bW\x1e:\xf9yfVn.\x07\x1f!F\xf0\xc7\
+\xcd\x9b\x0b*&N\x9f?\x93@\x99*+\xe4/T\
+\xe0\xd3\x82\xca\xa8)!~yL\xaf\x8bA\x83\x1a\xe9\
+#\x13`O6\xa3\xc1\xc5\x10\x0a\x9f\x0a\xd8\x90\xcb\x87\
+@\x83\x17 \x04\xfaX\x13tv\xe3\xa9\xc6Y\x0d\xc4\
+X\x05\xb4\xb5\xf8q\xf0\xd3\x1a\x04[\xc3\xbd/@\xc9\
+\xber=\xdd\xb5\x9b\x82?\xc79\x99\xc7)/\xdbZ\
+T\xb0f\x92#\xb7\x1f'\xe4I\x0e\xfew\x1d\xaf~\
+\xd9\xe9tF\x00`\xe2\xf4\x9c\x91\x9c\x93\xc7\x05NV\
+\x17;\x97\x17w\xd9zc\xc6\xe4i\x8d\xd1\xde<F\
+\x01U\x84\xbf\xb0ysA\x05\x00\xdc4eA\xacF\
+%?\xcaA\x86\x80\xe3\xb9\xad\xce\xfcMc\xc6\xe4\x89\
+;w\xe6\xc9\xe3\xb2r\xae\x8b\xb0Q\xeb\xc2HOg\
+\xdc\xd0k\xe7\xcd1Q\x18\xf4\xb3>P\x04\x15\x5c\xee\
+\xce\xfd^\xa7lC\xdb\xfb<\x15\x14\x1c\xdb]\x87\x86\
+c\xee\xefQ\x93\x85\xa1Ay\xb9\x06_\xe6\x96\xbdY\
+P\x06p\x02\x10\x9e9}\xc1-\xe0\xca\x03\x9c\xa0B\
+\x11\xcd9e\xaf\xe7\xb5\x02\x80\xc3\x91\x1d\xd3F\xc4\xf9\
+\x04\x90h\xc8\xbb\xe4\xf4\xc8#\xdd\x91\xb5\xc00\x8fp\
+ZQw\xd4\xff\xec\xe9)t\xf2\xe4\x1c\x8b\xac\xa1\x0f\
+\x83\xf3\x0cF\xe8\xf6\xd2\xc2\xa5/e=\x17\x99\xc9\x82\
+\x81\xb5\xad\xb5~\xc1_\xe3\x06\xbe\xc78*iP4\
+\xfa\x0c\x8aAP\x11\xe1\xf6\x9d\xe2/B\x00\x8b\x91\xc2\
+\xa8\xe5\xa8\xda\xd7\x88\x9a\xf2\xe6^e\xca\x93\x15|T\
+\x82\x0d\x86D\xbdG\xd4\xeb\xe7\x1fy\xf5\x81uI\xe9\
+Q\xd3\x18\xe5\xb7\x81\xd2}\xac5\xb4\xb2\xb4\xf4T\xb2\
+\x1a\x959[\x9f\xa0\x8f\x9a\x0b\xf0\xc1r\x18\x7fx\xfb\
+D\x80\xf4\xba2\x9f8c\xee\x0dP\xc4\x1c\x85\xf0\xd5\
+\xa3\x07\x9b\xb7}\xbe\xdf{'%\xb8\x81\x81?\xb5\xad\
+\xa8\xe0@fV\xcem\xa6A\x93\x17(1\xd7\x8d\xe4\
+'\xb0\x91C\x11\xb8\x0f\xd5!\xe4\xf2\xf7^\xc2P\x0b\
+\xe8;*\x11\xf1}m\x08\x8698\x07t\x1a\xc0]\
+\xef\xc7\xc1\x8f\xab\x11n\xeb}\xe7\xa1\xb1\xe8a\x1b\x90\
+\x08Q\xaf\xe9h\xac\xa9\xeb\xa3\xc3\xad\x07\x8a\x1f/)\
+\x5c\xb6n\xe2\xb4\x07\xfbC\x94\xf38\xc7\xdf\xb6m\xc8\
+\x7fuR\xd6\xbc_0\xce\xfe\x9b\x13a\xcd\xb6\x0d\xcb\
+\xb6\xff\xe0\x16&//\x8f\xee\xda\xef\x99\x03\x90\xe1\xe0\
+\xec\xdd\xad\xce\x15E\x9d\xe6z\xcfz^\xb6$\x9a~\
+\xe5\xf20\xf8\xdbNER[c+\xbcG\x1b \x87\
+z\xff\x90z\x93\x16\xd6D#\x08\x01\xbcM\x01\xf8\x9a\
+\xdb\xce\xd8\xaez\x08j\x01-5]\x8bV\x95N\x03\
+Sz\x0c\xf4\xb1\xe6S\xd7\xd3\x12\xd8\xcc\x94\xb5\xd6\xb5\
+\xbe\xf2\xe2\x03\x96_\x9f\xbe~|Vn\x16!\xb8\x9d\
+3|X\xea\xcc\x7f\xe6_\xde\xeb];u\xf7+\xe6\
+X\xc3\xed\xfd\xaeNV\x04\xbdF\xe7\xf2(\x88H'\
+\xeb%\x0e\x7fm\x0b|\xc7\x9b\xa1\x84\x7f\xf8\xc9\x9c(\
+\x8b\x16\x1a\xbd\x0a\xb6$#B\xfeH\xa7^\x8f\x88\x14\
+\xa6d;\x8c\xa91\x1dm\x92Z\x0d\xd8\xcd\x14\x92\xaf\
+\x8d\x1f\xdeU\xc7}M\x81W?z\xeb\x8a{/\xf8\
+\xb8\xca\xdb\x14P\x7fQz\x90\xc5gXy\xea\xb0X\
+\x22\x11\x15<^\x06\x09\x04\xc6d;t\xd1&\xb4V\
+4\xa2\xad\xc1\x0b\xce{\xcf_*\xad\x08\xbdI\x03[\
+\x92\x11L\xe1\xa7\x9a\xe6\x93\x11\x13k\x86)=\x16*\
+\x9d\xba\x83\xd7lf\x0a\xad\xa0\xb0\xea\xbd\xf5\xbc\xf6p\
+\x0ba\x92B/\xaaq\x158\xa7\xf5GZ\xe0\xae\xf5\
+)\x89\x03\xa3\x95\xf8\x016Uk\x1b!\xbe\x00\x87\xa8\
+U\xc1vY\x12\x0c\xc96x\x0e7 \xec\xe9\xdd\xb9\
+\x89\xc4~6\x08j\x01\x9cs\x10\x00\x8d\x15\x1e\xb4y\
+\xc3P\x1bu\xb0\xf4\x8d\x87\xc6r\xaa\xcf3\x1b\x08\xac\
+f\x8a\xe3{\x1bP}\xa0\x99\xca\x11\x05\xf7\xdcp\x1c\
+\xbb\x8e\x98\xb1\xb7\xe2b\x1cW\x05%\xe1\xd8\x9e:\xa1\
+\xee\xb0\x0b}\xafLTR\x12LB\xb3\x87\xa1-\xc8\
+\xa16\xe8\x10;\x22\x0dm\xf5\x1ex*\x1a\xbfS~\
+\xe1'\xc8\xc1u\xdc\x87\x90/\x0cY\xe1\xed\x873\x12\
+\xac \x94\x9c\xd0\xd1\x81h\x8b\x80\xa0\xbbM\xda\xb3\xbd\
+\x96\xf8\x9a\xdb\xc4\x1b\x85ChS\xa9\xd17>\x88\xd2\
+/b/\xeeqU\xc8\x1f\xc1\xbe\x9d\x15\x82%\xde\xc8\
+/\xbb&\x89\x98\xa2Tp\xb9\xdb\xe5^}\xbc\x05Z\
+\xbb\x11m\x0d^x\x8e\xd6w+\xef\x06\xbda\x04\x03\
+\x11\x04\xdc!\x18R\xec\x88I\x89\xee\xd0\xd4E\xa1}\
+\x5c%0\x19\xe5\x1fT\xa1\xa5\xd6\xa7\x8a\xe9\xe3\x83u\
+h\x04\xd7\x1d\xaa\xc4\x9f\xa5k\xf0\xfb\xd7\x0d?\x9eq\
+\x95\xa7\xdeG>\xd9\xfc-\x92\x07\xc5 mh\x0c\x02\
+\x92\x00\x97\x97\x81\xaa\x04\x18\x92m\xd0F\x1b\xe1=\xd6\
+\x80\xb6\x86\xae\xf2q\xd3q/\xb46\x03\xe2\xae\xea\x0b\
+\xd5\x89tO\x08`6PX\x8d@\xf5\xfe&T\xed\
+k\x84,\xb5\xd7W#n\xa8\xc2W\xef\xa5\xe0\xb1\xf0\
+\x8d?\xceq\x15\x00T\x1fhBs\x95\x07)\x83b\
+\xd0g@4\xbc\xbe\xf6~O\xd4\xaa`\x1f\x94\xdc\xae\
+W\x1d\xac\xeb8\xc4!\xea\xd5\xb0\xf6K\xe8t\xa4\xc7\
+\xa8oW-=5^|\xb2\xa3\x06\x913t\xf4\x1d\
+k\x07\xe3,\xda\x22\x08\xa8r\xee)\xeb\x1c\xed\xea)\
+{\x06\x08\x14\xdb\x09\x90\xf6}\xfa\xbdacR\xa16\
+\xe9P\xdb\xd8\xb9}\xe1\x0a\x03g\xbc\xd3\xd8J%\x02\
+16\x01,\x10\xc4\xa1\xcfk\xe1i\xec\xfd!:\x0e\
+\xd4sQ\xf8\xe5'E\x97\x1f\xb8\xa0\x11uE\xe6p\
+\x11L6\xc7\x86\x9b\xb0\xe7\xcb\x16\xb8<\xdf]/\x85\
+\xfc\x11|\xb6\xf5\x10\xe2\xd2\xcc\xc8\x18\x99\x88\xc8\x89q\
+\xbb\xa4\xb4\x8f\x99\xc8\x09\x8c(m\xaf\x87\xf4*\x86\xa3\
+\xbb\xabQ{\xa8\xf7\xc7\x19\x0dz\x8a\xd1\xd7\xc6\xc2\xad\
+\xb1\xb5IP\x91O\x8a.\xf0\xd6k\x0bJ\xf3\xef\xbf\
+Y\xb4\x8e\xee\x9b\x00\x97'\x1a\xafnl\xc0\xc62W\
+\xaf~\xdbP\xe1EC\x85\x17\x19#\xe2\x918\xc0\x0e\
+\x7f\x84\xb6O\x8fy{6\xb3\x18\x08j\xcb\x9b\xf0\xf5\
+7M\x90\xa5\xde\xed\x1eB\x80\x9f\x8f6c\xd1\x9c\x14\
+\x18\xa3\x04\xbc\xb7\x9fe\xbc\xf4\xbe\x94\x0d`\xce\xbfe\
+\xb80e\xca\x82\xd8\xb3}\xae3\xa8\x1e[\xf5\x8e\xb2\
+\xf1/\x7fW\xc0\x04\x15\xe6\xcdJ\xc6k\xf9\x031\xa4\
+\x7fT\xaf\x9d8\xba\xa7\x1e\xbbJ\x0e\x22\xd4\xe4\x81U\
+-\xc1\x1e\xa5\x00~?v\x95\x94\xe3\xc8\x97\xf5\x1d \
+\x09\x22\x85F\xd7\xfd,`\xf8 =\xfe\xfcD?,\
+^\x90\x06\x85\x08X\xfb\x0f\x86Wv\xb2\xf7\x94\xb0\xea\
+\xac\xc7\x12\xc7M\xcf\xee{\xde8j\xd2\x1d\x0f\x0cT\
+$\xb2\x88pb\xe4\xe0\xc7\xb9,\x15\x94\xbe\xb5\xaa\xe3\
+\xaf\x15\x99\xd3\xe7]\xc3\x81\x1c\xebe\xe3+Y\xdc\xf5\
+YY\xa3\x85\xb4_\x0e\xa60h\x81\xb7\xdfwcM\
+Q=\xea\x1a#\xe7\x9c\x0cD\x95\x80\xb4\x11q]Z\
+\x18\x00\x88\xb6\x8a\xf8\xf5\x8cxd\xde`GH\x02J\
+\xf70\xbc\xb3W)\x8f4~\xb3\xb1\xf1\xcb\xd7b\x14\
+N\x0b\xca\x9c\xcb\xf6\x9f\x5c\xefp\xe4\xdaB\x94\xcfa\
+\x0c\xfd\x08A\x1d\xe1\xf2\x8b%\xce\xe7\x8e\xfd \xa0&\
+O\xce\xb1DT\xf4^B\x90f\x12\xb4\x8b\xd7\xaf\x7f\
+\xb2a\xe2\xed\x0f\xf6\xe7\xb24\x1f\xa0\x9f\xe99\xdf\x1e\
+$\xec>\x80\xc8V\x8d\xb8t\xdd\xba\xa5\x81)3\x1f\
+\x9c\xa8\xc9\xb8%;~\xe05\x03\xa6]I\xd2~:\
+\x90\xa2-\xc8\xb0nS\x03\xde\xda\xee\x82?\xf0\xfd\x93\
+\x0f\xa1\x04\x89\xfd\xed\x105\x02T\x1a\x01\xa1@\x04\xd5\
+\xfb\xdb\x81\xd2i)\x1c\xe3\xa3q\xf7\xb4xh5\x04\
+\xdf\x1c\xe7X\xff\x11\xf3\x1c\xfe\xe6\x93j\xb9b\xdb\xd2\
+M\xaf?\xf5\xea\xa4I\xf7\x1ae\xad\xe9a\x01\x84B\
+\x91\xd6BP\xdf\xc4\xc1\xae&\x8a\xf0\xa7\x92\x8d\xcb\xbe\
+\xbd\xe9\xce\xfbbUa\xdd\x22\x01\xc4\x0dAY]\xbc\
+~EC\xaf\x80\x1a\xecp\xa8\xd3\x912\x0b`#\x04\
+\x82\xbf\x16o(\xf8\x10\x00~\xe2\xc8\xd5Y\x18\xb9\xac\
+l\xe3\xf2\xdd\x99Y9\x93\x01:\x81P\xe9\xf9\xe2\xc2\
+gw\xdf<\xfd\xfe\x91\x22W\xcd\xa6\x1c\xc7I\xb8u\
+\xa5j\xf8\xaf\xfb\xa9\xd5\xdam\xa3\xaf\x1a\x16?q\x04\
+%}\xe3\x08\xea\x1a#xiC=\xde~\xbf]\xdf\
+\xee\xdd\xb8\xca\x04\x83U\xdb1\xaeR\x14\x0e_s\x00\
+\x9e\x86\x00~>\xda\x8c;\xa7\xc4bP?=\x8e4\
+rl\xfa\x9c){\xf6|\xed\xd5\xb1\xc6\xc9\x87\x8f~\
+\xf2\xb9\xa1\xadu\x16\xe7,\x81I\xaaW\xca6?s\
+d\xc2\xd4\xdc\x0c\x22\xe07\x10\xc8\x8e\xad\x85\xcb\xdf\xbd\
+yZ\xee\x90\xe6\x8a\xc0\xc1\x93Z\xdb\xcd\xb7\xdd?D\
+T\xd4\xb3\x00\xb2w[\xd1\xb2W\xce\xec\x0f;\x015\
+nF\xf6\x15\x22\x13~\xcb\x18\xd9\xa9'\xd5N\xa7\xd3\
+\xa9\x00@\xe6\xad\xf3\xc7q\xca&\x11\x10?\xe7\x5c\xab\
+\x92#y\x9b6\xadr\x8d\x9b\x99m\xa2\xb2\xb0\x10\x5c\
+p\xcb\xb2\xef\x8d\xedo\xad\xae\x9b\xe0\xc8\x99\x03JF\
+1\x905\x833\x97)M\xae\x06\xe7O\x86D\xa7\xce\
+\xbcN\x80Q\x0b\xec\xfa\xc6\x8f\xd5o\xd4c\xdf\xa1\xef\
+N\xf1\xa9Cc!\xa8\x050\x99\xc1\xef\x0e\xa1\xf9\xb8\
+\x17}Su\x98{w\x02\xae\x1cfDD\x02\xde\xda\
+\xc5\xb0\xe3\xcb\x96\xe3\x01n\xb9\xab\xed\x1f\x0b\xea\x18!\
+\xd9\x9c\x93\xdd\xdb\x9c\xf9/\x8d\x9d\x91\x93\xa6b\xe4>\
+\x80\x8a\x11\xce\x9e\xdc\xee\xcco\xc9\xbcm~4g\xca\
+\xc3\x04\x82\x9f16\x94\x10\xf2\xd2\xd6\x0d\xcbKO\xd3\
+\xcf\xef\xa6\x84\x8f!\x84\xac*.\xcc\xdf\xd5\x09\xa8\x89\
+\x8e\xb9}\x00q\x11'Ju B\x9e\xdf\xb9\xb9\xc0\
+\x03\x00\x99\xb7\xe5\x0e\xe1\x0a\xf2@\xf0\x191\x07V\x95\
+\xac^\xdd6ujnFD\x85\xdf\x00\xd0\x81\xa3\x0f\
+\xa7d\xe9\xb6\xc2\xe5\x1fMt\xe4\xfc\x84\x80\xdc\xa3\x00\
+\x9bJ\x9d\xf9o\x8fsd\x0f\x16\x88\xf0\x18\x08\xf9\x22\
+i\xdc3\x95Q\x22\x16\xffb0I\x1f;\x9c\x82\x12\
+\xa0\xec\xbd\x16\xac\xd9P\x8f\xc6f\xa9\xc7q\x95,)\
+\xa8;\xd4\x02\xabI\xc0\xad\xe3\xa2\xe1\x98\x10\x03\xbd\x96\
+\xa2\xec+\x86\xed_\xf3\xa3m\x11\xb6\xb8n\xc7\xc3j\
+p>L&l\xc9\xdb\x85\x05\x15\x93\xa6\xcfs0\xce\
+o\x13\x80\xe7\xb7l\xc8\xdf1\xc9\xf1\xc0@\x85\x0a\x8b\
+\x08\xb8\x97p\xae\x85\x22\x14\x94l\x5c\xf6\xed\xec\xd9\xb3\
+U5n\xfd\xaf\x08\xc1U\x22\xc5\xe2\xcd\x85\xed\xca\xe6\
+\x09\x15\xf7^\x02>\x98\x04\xd9#\xc5\xc5+\x1a\xc8\xc9\
+Y\x9e \x10\xba\xa5p\xf9q\x00\xb8a\xca\xc3v\x9d\
+*2\x0b\xe0\x86\x88D\x9f\xfb\xdb\xa6\xa5\x8d]\xce\x1c\
+L\xbb\x7f\xc8\xf6\x8d\xab\xf6M\xbd}~jD\xe6\x0f\
+r\xa242\xd1Z`\x88\xec\x0b\x04y\x9f\xf9 J\
+\x9c\xa4`\xe9\xf6\xb7\x0a\xea&L\xcf\x19\xa4QG=\
+\xa2\x1f>\xab6.>%w\xc6\xb5T\xbc2\x9d\xc2\
+\xed\x95\xb1\xe5\x1d\x17^,\xac\xefV\xf9\x94%\x05Y\
+\xe3\xa3qoV<\x8cQ\x02\x0e\xd6q\xbc\xf6!\xe3\
+\x87k\xfck\x02\xbb\x96E\x0b\x01\xdf#\x9b6\x15\x1c\
+\x18;#'\x8d*\xc8\x11\x08\x91}\x8d\xbb\x17\x99L\
+W\xeb\x98F\xba\x97\x10\x0cP\xe4\xc8\x92\xd2\xb7VU\
+\x8ew\xe4\x8c(u\x16\xec9\xfb\x88\x8e\xce\xe1`j\
+I#>\xfa\xb7uK\x03'?\xf7\xd3\xb0\xf7\x9fo\
+\xfc\xd9\xdd\x85\xa3\xc6e\xe5\x5c'p\xba\x90P\xf2\xa7\
+\x92\xa2e\xdd\xfe\xd3r\xdc\xb8l\x8dh\x14\xe7\x03$\
+>\xc2y\xdevg~\xcb\xa4\xe993\x19\xe8\x14\x81\
+(\xcfl)\x5c\xf1\xe9\x98\xc99\x16\x83\x9a>\x03\xc2\
+\x9bi\xd0\xfbdq\xf1\xcb\xbe\x19\xf9\xc14\xb5V\x95\
+wy\x1f\xdc}\xe7u\x14q\xe6v\xfeZ\xfab\x0d\
+>\xd9\xdd\xda\xe9\x1e\x83\xfa\xea\x913+\x09C\x07\xe8\
+\xd1\x1a\x04^\xda\xa9\xe0\xcbc\xfc\xcd\x18\x8b\xf8P\xfe\
+LrtT\xe6l}\xbc\xce\x90\x0d\xf0>\x8c\xcby\
+e\xceg\x9bnq\xe4^\xce\x80<F\xe1\xdcV\x94\
+_8~\xea\xfd\xa9\x82\xa8\xcef\x04\x81\xab\x06\x99\x1f\
+\xcb\xcb\xcb\xeb\xb6\xf1\x9b4)\xb7\x1f\xd7\xf0\xa7\x89@\
+\x9e:}\xdbu\x9f\xf58'=\x0f>s\xa6\x82\x93\
+\xe9\x84\xd3g\xb7:\x97\xfd\xb3}\xac5o\x1a\xe7\xfc\
+A\x05\xda\xcc2\xe7SM\xe3\xa7\xde\x9fJ\x05\xf5\xfb\
+\x80r\xc7V\xe7\xca\x7f\x9ey\x8d9/\xf1\x81~I\
+.\xbaa0\x1d>\xf5J\x0a\xa3\x0e\xd8s \x80\xaf\
+\xf7\x07\x00\x02\x0c\xe9\xaf\xc3\xa8\xcb\x8d\x88\xc8@\xc9n\
+\x86w\xf6\xf1c\x01?\xbf\xf7\xb5l\xd5\xce.\xfe\xdc\
+>\x7f\x14\x95\x95\x22\xceC?\xdf\xea|\xa1\xe6F\xc7\
+Cf-\x09\xbfK\x08\x7f\xb1\xa4h\xc5_\x00`\xca\
+\xf4\x05C%\xae<N\x08^-)\xca\xdf\xf2/\xed\
+\xf5\xc6:\xe6\x0c\x14\x89\xf6)\x02\xea,\xd9\xb0l\xfd\
+YC\x98\x93\xc79\xc8\x97\xdb\x8a\x96\x17\xdc\xe8\x98\xdb\
+GK\xe8\xef\xc1P\xedo\xde\xb3x\xe7\xce\x9d]\xfa\
+\x9b\xd9/+sT\x94/\x1c?\x82\xa4\x8d\x1f\xde\xb9\
+\xfe\xfd\xaa\x92\xe3/\x7fW<A\x89>\xf6\xcb\xb4\xa6\
+\x17\xef\xba9>p\xe6x\xcd\x10\xeb]\x00\xf0t\x95\
+\xa4[\xb8i\xd3\x93-\x99\x8e\xdc;\x002Y\xa0\xe2\
+\xc2\xcdE\xcf\x1c\xe9\x02jV\xce\xbd\x00\xb9\x99E\xc4\
+\xdf\x95m\xee\xfa\xfd9\x035qz\xce\xf3`\xdcK\
+\xc3\x9a'\x8b\x8b\x97t{$e\xf2\x8cEi2\x0f\
+\x95\x10\xd0\x87K\x8a\x96o\x05\x80\x89\xd3\xe6\xf6\x87 \
+\xfcU\xe0X\xb2\xc5\x99\xdf\xe5\x9f\x9a\xab\xde\xe3\x86\x0f\
+\xf6\xcb\xf3\x93\xcc\xe4\xd11\x83\x89\xa8\x12\x80\xcf\x8e2\
+^\xd9L\xfe\xaa\x88B\xce\xda_\x11\xcf\xd9&D\x9c\
+\x09\x8fPB\x1f:I\x11\x99\xd3\xe7M\x04\xf8\x1f\x05\
+\xc2\x1d'\x89\xf9l6*s\xb6>!*\xeaa\xae\
+\x10\xc2\xfc\xd2\x13ee\xcf\x86\xcf\x1bP'\x07\x9e\xdd\
+n\xc7\x09s\xac\xd4\xa0\xcf\x01W\xe2|\x11,:\x99\
+9o\xbf}\x8e\xb5U\xd1<\x0a\x0e\x9f\xe2\xcbx\xaa\
+\xacln\xb7N-\xde\xc2\xe3\x0e7*\xd7\x1850\
+E\x10\xdc\xfe\xc2]\xc6\xc6\xee\xd6\xdes\xcf=\xda\xe6\
+\xa0\xed1\xce\xb9A\xa4\xe4\x7fO&\xa2)S\xee\x8b\
+\x8d\xa8u\xbf'\x9c\xb8\xfc*q\xcd\xce\xd7\x97Tw\
+\xcf\xb3+5=\xf9s^e\x961c\xc6\x88\xa6\xd8\
+Q3\x15\xb0_\x10EY\xbc\xf5\xc48~\xd4\xa8\xd9\
+\xaa\x84\x8c\xa8\xdf\x82\xf0\xab\x08\x17\xf3J\x9cK\x8f\xfd\
++t\xae\x89w>\xd4\x07\xe1\xf0\x13`d\xe7\xd67\
+\xf3\xd7\x9e\x94[\xc7\xde\xb1p\xa0\x18\x91\x1e\x22\x9c\xff\
+\xa3\xc4Y\xb0\xf6\x82\xeaQ\xe3fd_!0\xf1\x11\
+\xae\xf0\xd2m\x1b\x0b^\xee\xe8\xffn\xcd\xbd\x89S>\
+\x93\x02\xabOV\xf6\xffj\x9bp\xeb\xdck\x09\x11\x1e\
+\xa6`/\x16;W\x14\x9fJ<\x0f8\x08\xa7\xf7@\
+\x22\xbf\xdb\xbai\xf9W\x17\x06\xa8\x99\x0b\x93=\x11\xc9\
+\xf5\xb13?\x08\x00\xe3\x1c\xd9\x83E*\xce\x03#\xc7\
+J\x9c\xcb\x17\xe3\xdfl\xb3g\xcfV\xd5y\xa3~\xc3\
+\x19\x06\x10H+N6\xba?q\xe4\xeabDf\xea\
+\xae\x8f\xfb\xb7l\xbd\x8e\x1a\xc4\x91;V!d\x8c\x10\
+R\xf2\x8b\x8b\x7f\xb8C\xe7\xc3\xc69\xb2c\x04\xaaZ\
+\xc4\x99\xf2\xfe\xb6\xd3\xa2\xeb\xe2\xb0\xb3\x89\xd5\x17\xd8\xf2\
+\xf2\xf2(.\xd9%\xbbd\x97\xec?\xc0\xfe\x0f\x14\xd5\
+\xea\x92\xe4\xa3Oi\x00\x00\x00\x00IEND\xaeB\
+`\x82\
+\x00\x00\x012\
+<\
+svg width=\x2248\x22 h\
+eight=\x2248\x22 viewB\
+ox=\x220 0 48 48\x22 f\
+ill=\x22none\x22 xmlns\
+=\x22http://www.w3.\
+org/2000/svg\x22>\x0a<\
+path d=\x22M12.4501\
+ 37.65L10.3501 3\
+5.55L21.9001 24L\
+10.3501 12.45L12\
+.4501 10.35L24.0\
+001 21.9L35.5501\
+ 10.35L37.6501 1\
+2.45L26.1001 24L\
+37.6501 35.55L35\
+.5501 37.65L24.0\
+001 26.1L12.4501\
+ 37.65Z\x22 fill=\x22#\
+667085\x22/>\x0a</svg>\
+\x0a\
+\x00\x00\x04\x83\
+<\
+svg width=\x2248\x22 h\
+eight=\x2248\x22 viewB\
+ox=\x220 0 48 48\x22 f\
+ill=\x22none\x22 xmlns\
+=\x22http://www.w3.\
+org/2000/svg\x22>\x0a<\
+path d=\x22M10.3929\
+ 26.4C9.73097 26\
+.4 9.16667 26.16\
+43 8.7 25.6929C8\
+.23333 25.2215 8\
+ 24.6548 8 23.99\
+29C8 23.3309 8.2\
+357 22.7666 8.70\
+71 22.3C9.17847 \
+21.8333 9.74513 \
+21.6 10.4071 21.\
+6C11.069 21.6 11\
+.6333 21.8357 12\
+.1 22.3071C12.56\
+67 22.7784 12.8 \
+23.3451 12.8 24.\
+0071C12.8 24.669\
+ 12.5643 25.2333\
+ 12.0929 25.7C11\
+.6215 26.1666 11\
+.0549 26.4 10.39\
+29 26.4ZM23.9929\
+ 26.4C23.331 26.\
+4 22.7667 26.164\
+3 22.3 25.6929C2\
+1.8333 25.2215 2\
+1.6 24.6548 21.6\
+ 23.9929C21.6 23\
+.3309 21.8357 22\
+.7666 22.3071 22\
+.3C22.7785 21.83\
+33 23.3451 21.6 \
+24.0071 21.6C24.\
+669 21.6 25.2333\
+ 21.8357 25.7 22\
+.3071C26.1667 22\
+.7784 26.4 23.34\
+51 26.4 24.0071C\
+26.4 24.669 26.1\
+643 25.2333 25.6\
+929 25.7C25.2215\
+ 26.1666 24.6549\
+ 26.4 23.9929 26\
+.4ZM37.5929 26.4\
+C36.931 26.4 36.\
+3667 26.1643 35.\
+9 25.6929C35.433\
+3 25.2215 35.2 2\
+4.6548 35.2 23.9\
+929C35.2 23.3309\
+ 35.4357 22.7666\
+ 35.9071 22.3C36\
+.3785 21.8333 36\
+.9451 21.6 37.60\
+71 21.6C38.269 2\
+1.6 38.8333 21.8\
+357 39.3 22.3071\
+C39.7667 22.7784\
+ 40 23.3451 40 2\
+4.0071C40 24.669\
+ 39.7643 25.2333\
+ 39.2929 25.7C38\
+.8215 26.1666 38\
+.2549 26.4 37.59\
+29 26.4Z\x22 fill=\x22\
+#667085\x22/>\x0a</svg\
+>\x0a\
+\x00\x00\x037\
+<\
+svg width=\x2224\x22 h\
+eight=\x2224\x22 viewB\
+ox=\x220 0 24 24\x22 f\
+ill=\x22none\x22 xmlns\
+=\x22http://www.w3.\
+org/2000/svg\x22>\x0a<\
+path d=\x22M0 12C0 \
+5.37258 5.37258 \
+0 12 0C18.6274 0\
+ 24 5.37258 24 1\
+2C24 18.6274 18.\
+6274 24 12 24C5.\
+37258 24 0 18.62\
+74 0 12Z\x22 fill=\x22\
+#E6E6E6\x22/>\x0a<path\
+ d=\x22M15.5 12C16.\
+3284 12 17 12.67\
+16 17 13.5V14C17\
+ 15.9714 15.1405\
+ 18 12 18C8.8595\
+1 18 7 15.9714 7\
+ 14V13.5C7 12.67\
+16 7.67157 12 8.\
+5 12H15.5ZM15.5 \
+13H8.5C8.22386 1\
+3 8 13.2239 8 13\
+.5V14C8 15.4376 \
+9.43216 17 12 17\
+C14.5678 17 16 1\
+5.4376 16 14V13.\
+5C16 13.2239 15.\
+7761 13 15.5 13Z\
+M12 5.5C13.5188 \
+5.5 14.75 6.7312\
+2 14.75 8.25C14.\
+75 9.76878 13.51\
+88 11 12 11C10.4\
+812 11 9.25 9.76\
+878 9.25 8.25C9.\
+25 6.73122 10.48\
+12 5.5 12 5.5ZM1\
+2 6.5C11.0335 6.\
+5 10.25 7.2835 1\
+0.25 8.25C10.25 \
+9.2165 11.0335 1\
+0 12 10C12.9665 \
+10 13.75 9.2165 \
+13.75 8.25C13.75\
+ 7.2835 12.9665 \
+6.5 12 6.5Z\x22 fil\
+l=\x22#616161\x22/>\x0a</\
+svg>\x0a\x0a\
+\x00\x00\x00\xdf\
+<\
+svg width=\x2248\x22 h\
+eight=\x2248\x22 viewB\
+ox=\x220 0 48 48\x22 f\
+ill=\x22none\x22 xmlns\
+=\x22http://www.w3.\
+org/2000/svg\x22>\x0a<\
+path d=\x22M18.9002\
+ 35.7L7.7002 24.\
+5L9.8502 22.35L1\
+8.9002 31.4L38.1\
+002 12.2L40.2502\
+ 14.35L18.9002 3\
+5.7Z\x22 fill=\x22#667\
+085\x22/>\x0a</svg>\x0a\
+\x00\x00\x01V\
+<\
+svg width=\x2248\x22 h\
+eight=\x2248\x22 viewB\
+ox=\x220 0 48 48\x22 f\
+ill=\x22none\x22 xmlns\
+=\x22http://www.w3.\
+org/2000/svg\x22>\x0a<\
+path d=\x22M9 42C8.\
+2 42 7.5 41.7 6.\
+9 41.1C6.3 40.5 \
+6 39.8 6 39V9C6 \
+8.2 6.3 7.5 6.9 \
+6.9C7.5 6.3 8.2 \
+6 9 6H23.55V9H9V\
+39H23.55V42H9ZM3\
+3.3 32.75L31.15 \
+30.6L36.25 25.5H\
+18.75V22.5H36.15\
+L31.05 17.4L33.2\
+ 15.25L42 24.05L\
+33.3 32.75Z\x22 fil\
+l=\x22#667085\x22/>\x0a</\
+svg>\x0a\
+\x00\x00\x01f\
+<\
+svg width=\x2248\x22 h\
+eight=\x2248\x22 viewB\
+ox=\x220 0 48 48\x22 f\
+ill=\x22none\x22 xmlns\
+=\x22http://www.w3.\
+org/2000/svg\x22>\x0a<\
+path d=\x22M24.45 4\
+2V39H39V9H24.45V\
+6H39C39.8 6 40.5\
+ 6.3 41.1 6.9C41\
+.7 7.5 42 8.2 42\
+ 9V39C42 39.8 41\
+.7 40.5 41.1 41.\
+1C40.5 41.7 39.8\
+ 42 39 42H24.45Z\
+M20.55 32.75L18.\
+4 30.6L23.5 25.5\
+H6V22.5H23.4L18.\
+3 17.4L20.45 15.\
+25L29.25 24.05L2\
+0.55 32.75Z\x22 fil\
+l=\x22#667085\x22/>\x0a</\
+svg>\x0a\
+"
+
+qt_resource_name = b"\
+\x00\x02\
+\x00\x00\x07\x84\
+\x00q\
+\x00t\
+\x00\x03\
+\x00\x00x<\
+\x00q\
+\x00m\x00l\
+\x00\x0c\
+\x0fN\xa7E\
+\x00C\
+\x00o\x00l\x00o\x00r\x00P\x00a\x00l\x00e\x00t\x00t\x00e\
+\x00\x05\
+\x00o\xa6S\
+\x00i\
+\x00c\x00o\x00n\x00s\
+\x00\x08\
+\x03\xc6T'\
+\x00p\
+\x00l\x00u\x00s\x00.\x00s\x00v\x00g\
+\x00\x0c\
+\x07\x11\xd4\xa7\
+\x00u\
+\x00s\x00e\x00r\x00M\x00a\x00s\x00k\x00.\x00s\x00v\x00g\
+\x00\x06\
+\x07\x87WG\
+\x00q\
+\x00t\x00.\x00p\x00n\x00g\
+\x00\x0a\
+\x08\xab\xd7\x87\
+\x00u\
+\x00p\x00d\x00a\x00t\x00e\x00.\x00s\x00v\x00g\
+\x00\x0a\
+\x0c\xad\x02\x87\
+\x00d\
+\x00e\x00l\x00e\x00t\x00e\x00.\x00s\x00v\x00g\
+\x00\x08\
+\x0b\x07W\xa7\
+\x00e\
+\x00d\x00i\x00t\x00.\x00s\x00v\x00g\
+\x00\x0e\
+\x05\x92p\xc7\
+\x00t\
+\x00e\x00s\x00t\x00s\x00e\x00r\x00v\x00e\x00r\x00.\x00p\x00n\x00g\
+\x00\x09\
+\x06\x98\x8e\xa7\
+\x00c\
+\x00l\x00o\x00s\x00e\x00.\x00s\x00v\x00g\
+\x00\x08\
+\x06\xb6W\xa7\
+\x00d\
+\x00o\x00t\x00s\x00.\x00s\x00v\x00g\
+\x00\x08\
+\x09\xc5UG\
+\x00u\
+\x00s\x00e\x00r\x00.\x00s\x00v\x00g\
+\x00\x06\
+\x07^Z\xc7\
+\x00o\
+\x00k\x00.\x00s\x00v\x00g\
+\x00\x0a\
+\x06\xc91\x07\
+\x00l\
+\x00o\x00g\x00o\x00u\x00t\x00.\x00s\x00v\x00g\
+\x00\x09\
+\x0e\x01\xbcg\
+\x00l\
+\x00o\x00g\x00i\x00n\x00.\x00s\x00v\x00g\
+"
+
+qt_resource_struct = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x0a\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x16\x00\x02\x00\x00\x00\x01\x00\x00\x00\x04\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x004\x00\x02\x00\x00\x00\x0d\x00\x00\x00\x05\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00D\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x00\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x13\x96\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x00\xf6\x00\x00\x00\x00\x00\x01\x00\x00.-\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x01\x0e\x00\x00\x00\x00\x00\x01\x00\x00/c\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x01L\x00\x00\x00\x00\x00\x01\x00\x008\x08\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x00Z\x00\x00\x00\x00\x00\x01\x00\x00\x00\xc4\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x01:\x00\x00\x00\x00\x00\x01\x00\x007%\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x00x\x00\x00\x00\x00\x00\x01\x00\x00\x01\x5c\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x00\x8a\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xf3\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x01$\x00\x00\x00\x00\x00\x01\x00\x003\xea\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x00\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x11\x9b\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x00\xa4\x00\x00\x00\x00\x00\x01\x00\x00\x0f\xe4\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+\x00\x00\x01f\x00\x00\x00\x00\x00\x01\x00\x009b\
+\x00\x00\x01\x8d\x87\xa2.\x0a\
+"
+
+def qInitResources():
+    QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+def qCleanupResources():
+    QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+qInitResources()
diff --git a/examples/demos/colorpaletteclient/restservice.py b/examples/demos/colorpaletteclient/restservice.py
new file mode 100644 (file)
index 0000000..d334ecd
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtCore import Property, Signal, ClassInfo
+from PySide6.QtNetwork import (QNetworkAccessManager, QRestAccessManager,
+                               QNetworkRequestFactory, QSslSocket)
+from PySide6.QtQml import QmlElement, QPyQmlParserStatus, ListProperty
+from abstractresource import AbstractResource
+
+QML_IMPORT_NAME = "ColorPalette"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+@ClassInfo(DefaultProperty="resources")
+class RestService(QPyQmlParserStatus):
+
+    urlChanged = Signal()
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.m_resources = []
+        self.m_qnam = QNetworkAccessManager()
+        self.m_qnam.setAutoDeleteReplies(True)
+        self.m_manager = QRestAccessManager(self.m_qnam)
+        self.m_serviceApi = QNetworkRequestFactory()
+
+    @Property(str, notify=urlChanged)
+    def url(self):
+        return self.m_serviceApi.baseUrl()
+
+    @url.setter
+    def url(self, url):
+        if self.m_serviceApi.baseUrl() != url:
+            self.m_serviceApi.setBaseUrl(url)
+            self.urlChanged.emit()
+
+    @Property(bool, constant=True)
+    def sslSupported(self):
+        return QSslSocket.supportsSsl()
+
+    def classBegin(self):
+        pass
+
+    def componentComplete(self):
+        for resource in self.m_resources:
+            resource.setAccessManager(self.m_manager)
+            resource.setServiceApi(self.m_serviceApi)
+
+    def appendResource(self, r):
+        self.m_resources.append(r)
+
+    resources = ListProperty(AbstractResource, appendResource)
index d582edd09b36dad65b1d7bfa65156f4f63bf2932..1e5a34ca0cfb0e39072d16eb84ef0a54e408bffd 100644 (file)
@@ -184,13 +184,13 @@ class JsonViewer(AbstractViewer):
         menu = self.addMenu("Json")
         tb = self.addToolBar("Json Actions")
 
-        zoomInIcon = QIcon.fromTheme("zoom-in")
+        zoomInIcon = QIcon.fromTheme(QIcon.ThemeIcon.ZoomIn)
         a = menu.addAction(zoomInIcon, "&+Expand all", self._tree.expandAll)
         tb.addAction(a)
         a.setPriority(QAction.LowPriority)
         a.setShortcut(QKeySequence.New)
 
-        zoomOutIcon = QIcon.fromTheme("zoom-out")
+        zoomOutIcon = QIcon.fromTheme(QIcon.ThemeIcon.ZoomOut)
         a = menu.addAction(zoomOutIcon, "&-Collapse all", self._tree.collapseAll)
         tb.addAction(a)
         a.setPriority(QAction.LowPriority)
index 63d25bf702b93e735274fa48e134d621c9e1b11e..d5695e4d0aad09cfb2250712badb2159be882c78 100644 (file)
@@ -62,13 +62,17 @@ class PdfViewer(AbstractViewer):
 
         actionZoomIn = self._toolBar.addAction("Zoom in")
         actionZoomIn.setToolTip("Increase zoom level")
-        actionZoomIn.setIcon(QIcon(":/demos/documentviewer/images/zoom-in.png"))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.ZoomIn,
+                               QIcon(":/demos/documentviewer/images/zoom-in.png"))
+        actionZoomIn.setIcon(icon)
         self._toolBar.addAction(actionZoomIn)
         actionZoomIn.triggered.connect(self.onActionZoomInTriggered)
 
         actionZoomOut = self._toolBar.addAction("Zoom out")
         actionZoomOut.setToolTip("Decrease zoom level")
-        actionZoomOut.setIcon(QIcon(":/demos/documentviewer/images/zoom-out.png"))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.ZoomIn,
+                               QIcon(":/demos/documentviewer/images/zoom-out.png"))
+        actionZoomOut.setIcon(icon)
         self._toolBar.addAction(actionZoomOut)
         actionZoomOut.triggered.connect(self.onActionZoomOutTriggered)
 
index 27f81ecb73a1f2d19d673be34854abb0fe93de20..ef5a38fcde9a5a3867056986bdc4fa970ca58d56 100644 (file)
@@ -28,7 +28,7 @@ class TxtViewer(AbstractViewer):
     def setupTxtUi(self):
         editMenu = self.addMenu("Edit")
         editToolBar = self.addToolBar("Edit")
-        cutIcon = QIcon.fromTheme("edit-cut",
+        cutIcon = QIcon.fromTheme(QIcon.ThemeIcon.EditCut,
                                   QIcon(":/demos/documentviewer/images/cut.png"))
         cutAct = QAction(cutIcon, "Cut", self)
         cutAct.setShortcuts(QKeySequence.Cut)
@@ -37,7 +37,7 @@ class TxtViewer(AbstractViewer):
         editMenu.addAction(cutAct)
         editToolBar.addAction(cutAct)
 
-        copyIcon = QIcon.fromTheme("edit-copy",
+        copyIcon = QIcon.fromTheme(QIcon.ThemeIcon.EditCopy,
                                    QIcon(":/demos/documentviewer/images/copy.png"))
         copyAct = QAction(copyIcon, "Copy", self)
         copyAct.setShortcuts(QKeySequence.Copy)
@@ -46,7 +46,7 @@ class TxtViewer(AbstractViewer):
         editMenu.addAction(copyAct)
         editToolBar.addAction(copyAct)
 
-        pasteIcon = QIcon.fromTheme("edit-paste",
+        pasteIcon = QIcon.fromTheme(QIcon.ThemeIcon.EditPaste,
                                     QIcon(":/demos/documentviewer/images/paste.png"))
         pasteAct = QAction(pasteIcon, "Paste", self)
         pasteAct.setShortcuts(QKeySequence.Paste)
index 69ac09144f4a700a5e98b3a2dee6b2230383033d..5773ae5b8d21dcd7db8ce98cda8494307f123fe9 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'mainwindow.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.3
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -110,7 +110,7 @@ class Ui_MainWindow(object):
         self.splitter.addWidget(self.tabWidget)
         self.scrollArea = QScrollArea(self.splitter)
         self.scrollArea.setObjectName(u"scrollArea")
-        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth())
@@ -142,7 +142,7 @@ class Ui_MainWindow(object):
         MainWindow.setStatusBar(self.statusbar)
         self.mainToolBar = QToolBar(MainWindow)
         self.mainToolBar.setObjectName(u"mainToolBar")
-        MainWindow.addToolBar(Qt.TopToolBarArea, self.mainToolBar)
+        MainWindow.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.mainToolBar)
 
         self.menubar.addAction(self.qtFileMenu.menuAction())
         self.menubar.addAction(self.menuHelp.menuAction())
index a1b584fb95037ec48d5722de618a15afa7615a67..dd7fe1679ff8d787d8bfc73583a95294ce551738 100644 (file)
@@ -1,5 +1,7 @@
-Task Menu Extension (Designer)
-==============================
+.. _task-menu-extension-example:
+
+Task Menu Extension Example
+===========================
 
 This example shows how to add custom widgets to Qt Designer,
 which can be launched with `pyside6-designer`, and to extend
diff --git a/examples/graphs/2d/hellographs/HelloGraphs/Main.qml b/examples/graphs/2d/hellographs/HelloGraphs/Main.qml
new file mode 100644 (file)
index 0000000..b1844ae
--- /dev/null
@@ -0,0 +1,153 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Layouts
+import QtGraphs
+
+Item {
+    id: mainView
+    width: 1280
+    height: 720
+
+    RowLayout  {
+        id: graphsRow
+
+        readonly property real margin:  mainView.width * 0.02
+
+        anchors.fill: parent
+        anchors.margins: margin
+        spacing: margin
+
+        Rectangle {
+            Layout.fillHeight: true
+            Layout.fillWidth: true
+            color: "#262626"
+            border.color: "#4d4d4d"
+            border.width: 1
+            radius: graphsRow.margin
+            //! [bargraph]
+            GraphsView {
+                anchors.fill: parent
+                anchors.margins: 16
+                theme: GraphTheme {
+                    colorTheme: GraphTheme.ColorThemeDark
+                }
+                //! [bargraph]
+                //! [barseries]
+                BarSeries {
+                    axisX: BarCategoryAxis {
+                        categories: [2024, 2025, 2026]
+                        gridVisible: false
+                        minorGridVisible: false
+                    }
+                    axisY: ValueAxis {
+                        min: 20
+                        max: 100
+                        tickInterval: 10
+                        minorTickCount: 9
+                    }
+                    //! [barseries]
+                    //! [barset]
+                    BarSet {
+                        values: [82, 50, 75]
+                        borderWidth: 2
+                        color: "#373F26"
+                        borderColor: "#DBEB00"
+                    }
+                    //! [barset]
+                }
+            }
+        }
+
+        Rectangle {
+            Layout.fillHeight: true
+            Layout.fillWidth: true
+            color: "#262626"
+            border.color: "#4d4d4d"
+            border.width: 1
+            radius: graphsRow.margin
+
+            //! [linegraph]
+            GraphsView {
+                anchors.fill: parent
+                anchors.margins: 16
+                theme: GraphTheme {
+                    readonly property color c1: "#DBEB00"
+                    readonly property color c2: "#373F26"
+                    readonly property color c3: Qt.lighter(c2, 1.5)
+                    colorTheme: GraphTheme.ColorThemeDark
+                    gridMajorBarsColor: c3
+                    gridMinorBarsColor: c2
+                    axisXMajorColor: c3
+                    axisYMajorColor: c3
+                    axisXMinorColor: c2
+                    axisYMinorColor: c2
+                    axisXLabelsColor: c1
+                    axisYLabelsColor: c1
+                }
+                //! [linegraph]
+
+                //! [linemarker]
+                component Marker : Rectangle {
+                    width: 16
+                    height: 16
+                    color: "#ffffff"
+                    radius: width * 0.5
+                    border.width: 4
+                    border.color: "#000000"
+                }
+                //! [linemarker]
+
+                //! [lineseriestheme]
+                SeriesTheme {
+                    id: seriesTheme
+                    colors: ["#2CDE85", "#DBEB00"]
+                }
+                //! [lineseriestheme]
+
+                //! [lineseries1]
+                LineSeries {
+                    id: lineSeries1
+                    theme: seriesTheme
+                    axisX: ValueAxis {
+                        max: 5
+                        tickInterval: 1
+                        minorTickCount: 9
+                        labelDecimals: 1
+                    }
+                    axisY: ValueAxis {
+                        max: 10
+                        tickInterval: 1
+                        minorTickCount: 4
+                        labelDecimals: 1
+                    }
+                    width: 4
+                    pointMarker: Marker { }
+                    XYPoint { x: 0; y: 0 }
+                    XYPoint { x: 1; y: 2.1 }
+                    XYPoint { x: 2; y: 3.3 }
+                    XYPoint { x: 3; y: 2.1 }
+                    XYPoint { x: 4; y: 4.9 }
+                    XYPoint { x: 5; y: 3.0 }
+                }
+                //! [lineseries1]
+
+                //! [lineseries2]
+                LineSeries {
+                    id: lineSeries2
+                    theme: seriesTheme
+                    width: 4
+                    pointMarker: Marker { }
+                    XYPoint { x: 0; y: 5.0 }
+                    XYPoint { x: 1; y: 3.3 }
+                    XYPoint { x: 2; y: 7.1 }
+                    XYPoint { x: 3; y: 7.5 }
+                    XYPoint { x: 4; y: 6.1 }
+                    XYPoint { x: 5; y: 3.2 }
+                }
+                //! [lineseries2]
+            }
+        }
+    }
+}
diff --git a/examples/graphs/2d/hellographs/HelloGraphs/qmldir b/examples/graphs/2d/hellographs/HelloGraphs/qmldir
new file mode 100644 (file)
index 0000000..007f5fb
--- /dev/null
@@ -0,0 +1,2 @@
+module HelloGraphs
+Main 1.0 Main.qml
diff --git a/examples/graphs/2d/hellographs/doc/hellographs.rst b/examples/graphs/2d/hellographs/doc/hellographs.rst
new file mode 100644 (file)
index 0000000..d0820c3
--- /dev/null
@@ -0,0 +1,51 @@
+HelloGraphs Example
+===================
+
+The example shows how to make a simple 2D bar graph and line graph.
+
+BarGraph
+--------
+
+The first graph in the example is a bar graph. Creating it starts with a GraphsView
+component and setting the theme to one which is suitable on
+dark backgrounds. This theme adjusts the graph background grid and axis lines and
+labels.
+
+To make this a bar graph, add a ``BarSeries.`` The X axis of the series is a
+``BarCategoryAxis`` with 3 categories. We hide both the vertical grid and the
+axis lines. The Y axis of the series is ``ValueAxis`` with visible range
+between 20 and 100. Major ticks with labels will be shown on every 10 values
+using the ``tickInterval`` property. Minor ticks will be shown on every 1
+values setting the ``minorTickCount`` propertyt to 9, which means that between
+every major ticks there will be 9 minor ones.
+
+Then data is added into ``BarSeries`` using ``BarSet.`` There are 3 bars, and we define
+custom bars color and border properties. These properties will override the possible
+theme set for the ``AbstractSeries.``
+
+LineGraph
+---------
+
+The second graph of the example is a line graph. It also starts by defining a
+``GraphsView`` element. A custom ``GraphTheme`` is created to get a custom appearance.
+``GraphTheme`` offers quite a wide range of customization possibilities for the background
+grid and axis, which get applied after the ``colorTheme``.
+
+A custom ``Marker`` component is used to visualize the data points.
+
+The previous bar graph didn't define a separate ``SeriesTheme``, so it uses the
+default theme. This line graph uses a custom theme with the desired line colors.
+
+To make this a line graph, add a ``LineSeries.`` The first series defines
+``axisX`` and ``axisY`` for this graph. It also sets the ``pointMarker`` to use
+the custom ``Marker`` component that was created earlier. Data points are added
+using ``XYPoint`` elements.
+
+The second line series is similar to the first. The ``axisX`` and ``axisY``
+don't need to be defined as the graph already contains them. As this is the
+second ``LineSeries`` inside the ``GraphsView``, second color from the
+``seriesTheme`` gets automatically picked.
+
+.. image:: hellographs.webp
+   :width: 1293
+   :alt: HelloGraphs Screenshot
diff --git a/examples/graphs/2d/hellographs/doc/hellographs.webp b/examples/graphs/2d/hellographs/doc/hellographs.webp
new file mode 100644 (file)
index 0000000..3e76664
Binary files /dev/null and b/examples/graphs/2d/hellographs/doc/hellographs.webp differ
diff --git a/examples/graphs/2d/hellographs/hellographs.pyproject b/examples/graphs/2d/hellographs/hellographs.pyproject
new file mode 100644 (file)
index 0000000..e8e8cb2
--- /dev/null
@@ -0,0 +1,3 @@
+{
+    "files": ["main.py", "HelloGraphs/Main.qml", "HelloGraphs/qmldir"]
+}
diff --git a/examples/graphs/2d/hellographs/main.py b/examples/graphs/2d/hellographs/main.py
new file mode 100644 (file)
index 0000000..acc349b
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+"""PySide6 port of the Qt Hello Graphs example from Qt v6.x"""
+
+from pathlib import Path
+import sys
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtQuick import QQuickView
+
+
+if __name__ == '__main__':
+    app = QGuiApplication(sys.argv)
+
+    viewer = QQuickView()
+    viewer.engine().addImportPath(Path(__file__).parent)
+    viewer.setColor("black")
+    viewer.loadFromModule("HelloGraphs", "Main")
+    viewer.show()
+    r = app.exec()
+    del viewer
+    sys.exit(r)
diff --git a/examples/graphs/3d/minimalsurfacegraph/doc/minimalsurfacegraph.rst b/examples/graphs/3d/minimalsurfacegraph/doc/minimalsurfacegraph.rst
new file mode 100644 (file)
index 0000000..bfc7a04
--- /dev/null
@@ -0,0 +1,4 @@
+Minimal Surface Example
+=======================
+
+The example shows the minimal code to create a surface.
diff --git a/examples/graphs/3d/minimalsurfacegraph/main.py b/examples/graphs/3d/minimalsurfacegraph/main.py
new file mode 100644 (file)
index 0000000..5fb4b44
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import sys
+
+from PySide6.QtCore import QSize
+from PySide6.QtGui import QVector3D
+from PySide6.QtGraphs import (Q3DSurface, QSurfaceDataItem,
+                              QSurface3DSeries)
+from PySide6.QtWidgets import QApplication
+from PySide6.QtQuickWidgets import QQuickWidget
+
+
+DESCRIPTION = """Minimal Qt Graphs Surface Example
+
+Use the mouse wheel to zoom. Rotate using the right mouse button.
+"""
+
+
+if __name__ == '__main__':
+    app = QApplication(sys.argv)
+
+    print(DESCRIPTION)
+
+    surface = Q3DSurface()
+    axis = surface.axisX()
+    axis.setTitle("X")
+    axis.setTitleVisible(True)
+    axis = surface.axisY()
+    axis.setTitle("Y")
+    axis.setTitleVisible(True)
+    axis = surface.axisZ()
+    axis.setTitle("Z")
+    axis.setTitleVisible(True)
+
+    data = []
+    data_row1 = [QSurfaceDataItem(QVector3D(0, 0.1, 0.5)),
+                 QSurfaceDataItem(QVector3D(1, 0.5, 0.5))]
+    data.append(data_row1)
+    data_row2 = [QSurfaceDataItem(QVector3D(0, 1.8, 1)),
+                 QSurfaceDataItem(QVector3D(1, 1.2, 1))]
+    data.append(data_row2)
+
+    series = QSurface3DSeries()
+    series.dataProxy().resetArray(data)
+    surface.addSeries(series)
+
+    available_height = app.primaryScreen().availableGeometry().height()
+    width = available_height * 4 / 5
+    surface.resize(QSize(width, width))
+    surface.setResizeMode(QQuickWidget.SizeRootObjectToView)
+    surface.show()
+
+    sys.exit(app.exec())
diff --git a/examples/graphs/3d/widgetgallery/axesinputhandler.py b/examples/graphs/3d/widgetgallery/axesinputhandler.py
new file mode 100644 (file)
index 0000000..4c42029
--- /dev/null
@@ -0,0 +1,100 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from enum import Enum
+from math import sin, cos, degrees
+
+from PySide6.QtCore import Qt
+from PySide6.QtGraphs import QAbstract3DGraph, Q3DInputHandler
+
+
+class InputState(Enum):
+    StateNormal = 0
+    StateDraggingX = 1
+    StateDraggingZ = 2
+    StateDraggingY = 3
+
+
+class AxesInputHandler(Q3DInputHandler):
+
+    def __init__(self, graph, parent=None):
+        super().__init__(parent)
+        self._mousePressed = False
+        self._state = InputState.StateNormal
+        self._axisX = None
+        self._axisZ = None
+        self._axisY = None
+        self._speedModifier = 15.0
+
+        # Connect to the item selection signal from graph
+        graph.selectedElementChanged.connect(self.handleElementSelected)
+
+    def setAxes(self, axisX, axisZ, axisY):
+        self._axisX = axisX
+        self._axisZ = axisZ
+        self._axisY = axisY
+
+    def setDragSpeedModifier(self, modifier):
+        self._speedModifier = modifier
+
+    def mousePressEvent(self, event, mousePos):
+        super().mousePressEvent(event, mousePos)
+        if Qt.LeftButton == event.button():
+            self._mousePressed = True
+
+    def mouseMoveEvent(self, event, mousePos):
+        # Check if we're trying to drag axis label
+        if self._mousePressed and self._state != InputState.StateNormal:
+            self.setPreviousInputPos(self.inputPosition())
+            self.setInputPosition(mousePos)
+            self.handleAxisDragging()
+        else:
+            super().mouseMoveEvent(event, mousePos)
+
+    def mouseReleaseEvent(self, event, mousePos):
+        super().mouseReleaseEvent(event, mousePos)
+        self._mousePressed = False
+        self._state = InputState.StateNormal
+
+    def handleElementSelected(self, type):
+        if type == QAbstract3DGraph.ElementAxisXLabel:
+            self._state = InputState.StateDraggingX
+        elif type == QAbstract3DGraph.ElementAxisYLabel:
+            self._state = InputState.StateDraggingY
+        elif type == QAbstract3DGraph.ElementAxisZLabel:
+            self._state = InputState.StateDraggingZ
+        else:
+            self._state = InputState.StateNormal
+
+    def handleAxisDragging(self):
+        distance = 0.0
+        # Get scene orientation from active camera
+        xRotation = self.cameraXRotation()
+        yRotation = self.cameraYRotation()
+
+        # Calculate directional drag multipliers based on rotation
+        xMulX = cos(degrees(xRotation))
+        xMulY = sin(degrees(xRotation))
+        zMulX = sin(degrees(xRotation))
+        zMulY = cos(degrees(xRotation))
+
+        # Get the drag amount
+        move = self.inputPosition() - self.previousInputPos()
+
+        # Flip the effect of y movement if we're viewing from below
+        yMove = -move.y() if yRotation < 0 else move.y()
+
+        # Adjust axes
+        if self._state == InputState.StateDraggingX:
+            distance = (move.x() * xMulX - yMove * xMulY) / self._speedModifier
+            self._axisX.setRange(self._axisX.min() - distance,
+                                 self._axisX.max() - distance)
+        elif self._state == InputState.StateDraggingZ:
+            distance = (move.x() * zMulX + yMove * zMulY) / self._speedModifier
+            self._axisZ.setRange(self._axisZ.min() + distance,
+                                 self._axisZ.max() + distance)
+        elif self._state == InputState.StateDraggingY:
+            # No need to use adjusted y move here
+            distance = move.y() / self._speedModifier
+            self._axisY.setRange(self._axisY.min() + distance,
+                                 self._axisY.max() + distance)
diff --git a/examples/graphs/3d/widgetgallery/bargraph.py b/examples/graphs/3d/widgetgallery/bargraph.py
new file mode 100644 (file)
index 0000000..822acb4
--- /dev/null
@@ -0,0 +1,272 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from graphmodifier import GraphModifier
+
+from PySide6.QtCore import QObject, Qt
+from PySide6.QtGui import QFont
+from PySide6.QtWidgets import (QButtonGroup, QCheckBox, QComboBox, QFontComboBox,
+                               QLabel, QPushButton, QHBoxLayout, QSizePolicy,
+                               QRadioButton, QSlider, QVBoxLayout, QWidget)
+from PySide6.QtQuickWidgets import QQuickWidget
+from PySide6.QtGraphs import (QAbstract3DGraph, QAbstract3DSeries, Q3DBars)
+
+
+class BarGraph(QObject):
+
+    def __init__(self, minimum_graph_size, maximum_graph_size):
+        super().__init__()
+        self._barsGraph = Q3DBars()
+        self._barsWidget = QWidget()
+        hLayout = QHBoxLayout(self._barsWidget)
+        self._barsGraph.setMinimumSize(minimum_graph_size)
+        self._barsGraph.setMaximumSize(maximum_graph_size)
+        self._barsGraph.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        self._barsGraph.setFocusPolicy(Qt.StrongFocus)
+        self._barsGraph.setResizeMode(QQuickWidget.SizeRootObjectToView)
+        hLayout.addWidget(self._barsGraph, 1)
+
+        vLayout = QVBoxLayout()
+        hLayout.addLayout(vLayout)
+
+        themeList = QComboBox(self._barsWidget)
+        themeList.addItem("Qt")
+        themeList.addItem("Primary Colors")
+        themeList.addItem("Digia")
+        themeList.addItem("Stone Moss")
+        themeList.addItem("Army Blue")
+        themeList.addItem("Retro")
+        themeList.addItem("Ebony")
+        themeList.addItem("Isabelle")
+        themeList.setCurrentIndex(0)
+
+        labelButton = QPushButton(self._barsWidget)
+        labelButton.setText("Change label style")
+
+        smoothCheckBox = QCheckBox(self._barsWidget)
+        smoothCheckBox.setText("Smooth bars")
+        smoothCheckBox.setChecked(False)
+
+        barStyleList = QComboBox(self._barsWidget)
+        barStyleList.addItem("Bar", QAbstract3DSeries.Mesh.Bar)
+        barStyleList.addItem("Pyramid", QAbstract3DSeries.Mesh.Pyramid)
+        barStyleList.addItem("Cone", QAbstract3DSeries.Mesh.Cone)
+        barStyleList.addItem("Cylinder", QAbstract3DSeries.Mesh.Cylinder)
+        barStyleList.addItem("Bevel bar", QAbstract3DSeries.Mesh.BevelBar)
+        barStyleList.addItem("Sphere", QAbstract3DSeries.Mesh.Sphere)
+        barStyleList.setCurrentIndex(4)
+
+        cameraButton = QPushButton(self._barsWidget)
+        cameraButton.setText("Change camera preset")
+
+        zoomToSelectedButton = QPushButton(self._barsWidget)
+        zoomToSelectedButton.setText("Zoom to selected bar")
+
+        selectionModeList = QComboBox(self._barsWidget)
+        selectionModeList.addItem("None", QAbstract3DGraph.SelectionNone)
+        selectionModeList.addItem("Bar", QAbstract3DGraph.SelectionItem)
+        selectionModeList.addItem("Row", QAbstract3DGraph.SelectionRow)
+        sel = QAbstract3DGraph.SelectionItemAndRow
+        selectionModeList.addItem("Bar and Row", sel)
+        selectionModeList.addItem("Column", QAbstract3DGraph.SelectionColumn)
+        sel = QAbstract3DGraph.SelectionItemAndColumn
+        selectionModeList.addItem("Bar and Column", sel)
+        sel = QAbstract3DGraph.SelectionRowAndColumn
+        selectionModeList.addItem("Row and Column", sel)
+        sel = QAbstract3DGraph.SelectionItemRowAndColumn
+        selectionModeList.addItem("Bar, Row and Column", sel)
+        sel = QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionRow
+        selectionModeList.addItem("Slice into Row", sel)
+        sel = QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionItemAndRow
+        selectionModeList.addItem("Slice into Row and Item", sel)
+        sel = QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionColumn
+        selectionModeList.addItem("Slice into Column", sel)
+        sel = (QAbstract3DGraph.SelectionSlice
+               | QAbstract3DGraph.SelectionItemAndColumn)
+        selectionModeList.addItem("Slice into Column and Item", sel)
+        sel = (QAbstract3DGraph.SelectionItemRowAndColumn
+               | QAbstract3DGraph.SelectionMultiSeries)
+        selectionModeList.addItem("Multi: Bar, Row, Col", sel)
+        sel = (QAbstract3DGraph.SelectionSlice
+               | QAbstract3DGraph.SelectionItemAndRow
+               | QAbstract3DGraph.SelectionMultiSeries)
+        selectionModeList.addItem("Multi, Slice: Row, Item", sel)
+        sel = (QAbstract3DGraph.SelectionSlice
+               | QAbstract3DGraph.SelectionItemAndColumn
+               | QAbstract3DGraph.SelectionMultiSeries)
+        selectionModeList.addItem("Multi, Slice: Col, Item", sel)
+        selectionModeList.setCurrentIndex(1)
+
+        backgroundCheckBox = QCheckBox(self._barsWidget)
+        backgroundCheckBox.setText("Show background")
+        backgroundCheckBox.setChecked(False)
+
+        gridCheckBox = QCheckBox(self._barsWidget)
+        gridCheckBox.setText("Show grid")
+        gridCheckBox.setChecked(True)
+
+        seriesCheckBox = QCheckBox(self._barsWidget)
+        seriesCheckBox.setText("Show second series")
+        seriesCheckBox.setChecked(False)
+
+        reverseValueAxisCheckBox = QCheckBox(self._barsWidget)
+        reverseValueAxisCheckBox.setText("Reverse value axis")
+        reverseValueAxisCheckBox.setChecked(False)
+
+        reflectionCheckBox = QCheckBox(self._barsWidget)
+        reflectionCheckBox.setText("Show reflections")
+        reflectionCheckBox.setChecked(False)
+
+        rotationSliderX = QSlider(Qt.Horizontal, self._barsWidget)
+        rotationSliderX.setTickInterval(30)
+        rotationSliderX.setTickPosition(QSlider.TicksBelow)
+        rotationSliderX.setMinimum(-180)
+        rotationSliderX.setValue(0)
+        rotationSliderX.setMaximum(180)
+        rotationSliderY = QSlider(Qt.Horizontal, self._barsWidget)
+        rotationSliderY.setTickInterval(15)
+        rotationSliderY.setTickPosition(QSlider.TicksAbove)
+        rotationSliderY.setMinimum(-90)
+        rotationSliderY.setValue(0)
+        rotationSliderY.setMaximum(90)
+
+        fontSizeSlider = QSlider(Qt.Horizontal, self._barsWidget)
+        fontSizeSlider.setTickInterval(10)
+        fontSizeSlider.setTickPosition(QSlider.TicksBelow)
+        fontSizeSlider.setMinimum(1)
+        fontSizeSlider.setValue(30)
+        fontSizeSlider.setMaximum(100)
+
+        fontList = QFontComboBox(self._barsWidget)
+        fontList.setCurrentFont(QFont("Times New Roman"))
+
+        shadowQuality = QComboBox(self._barsWidget)
+        shadowQuality.addItem("None")
+        shadowQuality.addItem("Low")
+        shadowQuality.addItem("Medium")
+        shadowQuality.addItem("High")
+        shadowQuality.addItem("Low Soft")
+        shadowQuality.addItem("Medium Soft")
+        shadowQuality.addItem("High Soft")
+        shadowQuality.setCurrentIndex(5)
+
+        rangeList = QComboBox(self._barsWidget)
+        rangeList.addItem("2015")
+        rangeList.addItem("2016")
+        rangeList.addItem("2017")
+        rangeList.addItem("2018")
+        rangeList.addItem("2019")
+        rangeList.addItem("2020")
+        rangeList.addItem("2021")
+        rangeList.addItem("2022")
+        rangeList.addItem("All")
+        rangeList.setCurrentIndex(8)
+
+        axisTitlesVisibleCB = QCheckBox(self._barsWidget)
+        axisTitlesVisibleCB.setText("Axis titles visible")
+        axisTitlesVisibleCB.setChecked(True)
+
+        axisTitlesFixedCB = QCheckBox(self._barsWidget)
+        axisTitlesFixedCB.setText("Axis titles fixed")
+        axisTitlesFixedCB.setChecked(True)
+
+        axisLabelRotationSlider = QSlider(Qt.Horizontal, self._barsWidget)
+        axisLabelRotationSlider.setTickInterval(10)
+        axisLabelRotationSlider.setTickPosition(QSlider.TicksBelow)
+        axisLabelRotationSlider.setMinimum(0)
+        axisLabelRotationSlider.setValue(30)
+        axisLabelRotationSlider.setMaximum(90)
+
+        modeGroup = QButtonGroup(self._barsWidget)
+        modeWeather = QRadioButton("Temperature Data", self._barsWidget)
+        modeWeather.setChecked(True)
+        modeCustomProxy = QRadioButton("Custom Proxy Data", self._barsWidget)
+        modeGroup.addButton(modeWeather)
+        modeGroup.addButton(modeCustomProxy)
+
+        vLayout.addWidget(QLabel("Rotate horizontally"))
+        vLayout.addWidget(rotationSliderX, 0, Qt.AlignTop)
+        vLayout.addWidget(QLabel("Rotate vertically"))
+        vLayout.addWidget(rotationSliderY, 0, Qt.AlignTop)
+        vLayout.addWidget(labelButton, 0, Qt.AlignTop)
+        vLayout.addWidget(cameraButton, 0, Qt.AlignTop)
+        vLayout.addWidget(zoomToSelectedButton, 0, Qt.AlignTop)
+        vLayout.addWidget(backgroundCheckBox)
+        vLayout.addWidget(gridCheckBox)
+        vLayout.addWidget(smoothCheckBox)
+        vLayout.addWidget(reflectionCheckBox)
+        vLayout.addWidget(seriesCheckBox)
+        vLayout.addWidget(reverseValueAxisCheckBox)
+        vLayout.addWidget(axisTitlesVisibleCB)
+        vLayout.addWidget(axisTitlesFixedCB)
+        vLayout.addWidget(QLabel("Show year"))
+        vLayout.addWidget(rangeList)
+        vLayout.addWidget(QLabel("Change bar style"))
+        vLayout.addWidget(barStyleList)
+        vLayout.addWidget(QLabel("Change selection mode"))
+        vLayout.addWidget(selectionModeList)
+        vLayout.addWidget(QLabel("Change theme"))
+        vLayout.addWidget(themeList)
+        vLayout.addWidget(QLabel("Adjust shadow quality"))
+        vLayout.addWidget(shadowQuality)
+        vLayout.addWidget(QLabel("Change font"))
+        vLayout.addWidget(fontList)
+        vLayout.addWidget(QLabel("Adjust font size"))
+        vLayout.addWidget(fontSizeSlider)
+        vLayout.addWidget(QLabel("Axis label rotation"))
+        vLayout.addWidget(axisLabelRotationSlider, 0, Qt.AlignTop)
+        vLayout.addWidget(modeWeather, 0, Qt.AlignTop)
+        vLayout.addWidget(modeCustomProxy, 1, Qt.AlignTop)
+
+        self._modifier = GraphModifier(self._barsGraph, self)
+
+        rotationSliderX.valueChanged.connect(self._modifier.rotateX)
+        rotationSliderY.valueChanged.connect(self._modifier.rotateY)
+
+        labelButton.clicked.connect(self._modifier.changeLabelBackground)
+        cameraButton.clicked.connect(self._modifier.changePresetCamera)
+        zoomToSelectedButton.clicked.connect(self._modifier.zoomToSelectedBar)
+
+        backgroundCheckBox.stateChanged.connect(self._modifier.setBackgroundEnabled)
+        gridCheckBox.stateChanged.connect(self._modifier.setGridEnabled)
+        smoothCheckBox.stateChanged.connect(self._modifier.setSmoothBars)
+        seriesCheckBox.stateChanged.connect(self._modifier.setSeriesVisibility)
+        reverseValueAxisCheckBox.stateChanged.connect(self._modifier.setReverseValueAxis)
+        reflectionCheckBox.stateChanged.connect(self._modifier.setReflection)
+
+        self._modifier.backgroundEnabledChanged.connect(backgroundCheckBox.setChecked)
+        self._modifier.gridEnabledChanged.connect(gridCheckBox.setChecked)
+
+        rangeList.currentIndexChanged.connect(self._modifier.changeRange)
+
+        barStyleList.currentIndexChanged.connect(self._modifier.changeStyle)
+
+        selectionModeList.currentIndexChanged.connect(self._modifier.changeSelectionMode)
+
+        themeList.currentIndexChanged.connect(self._modifier.changeTheme)
+
+        shadowQuality.currentIndexChanged.connect(self._modifier.changeShadowQuality)
+
+        self._modifier.shadowQualityChanged.connect(shadowQuality.setCurrentIndex)
+        self._barsGraph.shadowQualityChanged.connect(self._modifier.shadowQualityUpdatedByVisual)
+
+        fontSizeSlider.valueChanged.connect(self._modifier.changeFontSize)
+        fontList.currentFontChanged.connect(self._modifier.changeFont)
+
+        self._modifier.fontSizeChanged.connect(fontSizeSlider.setValue)
+        self._modifier.fontChanged.connect(fontList.setCurrentFont)
+
+        axisTitlesVisibleCB.stateChanged.connect(self._modifier.setAxisTitleVisibility)
+        axisTitlesFixedCB.stateChanged.connect(self._modifier.setAxisTitleFixed)
+        axisLabelRotationSlider.valueChanged.connect(self._modifier.changeLabelRotation)
+
+        modeWeather.toggled.connect(self._modifier.setDataModeToWeather)
+        modeCustomProxy.toggled.connect(self._modifier.setDataModeToCustom)
+        modeWeather.toggled.connect(seriesCheckBox.setEnabled)
+        modeWeather.toggled.connect(rangeList.setEnabled)
+        modeWeather.toggled.connect(axisTitlesVisibleCB.setEnabled)
+        modeWeather.toggled.connect(axisTitlesFixedCB.setEnabled)
+        modeWeather.toggled.connect(axisLabelRotationSlider.setEnabled)
+
+    def barsWidget(self):
+        return self._barsWidget
diff --git a/examples/graphs/3d/widgetgallery/custominputhandler.py b/examples/graphs/3d/widgetgallery/custominputhandler.py
new file mode 100644 (file)
index 0000000..15fe00e
--- /dev/null
@@ -0,0 +1,177 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from enum import Enum
+from math import sin, cos, degrees
+
+from PySide6.QtCore import Qt
+from PySide6.QtGraphs import (QAbstract3DGraph, Q3DInputHandler)
+
+
+class InputState(Enum):
+    StateNormal = 0
+    StateDraggingX = 1
+    StateDraggingZ = 2
+    StateDraggingY = 3
+
+
+class CustomInputHandler(Q3DInputHandler):
+
+    def __init__(self, graph, parent=None):
+        super().__init__(parent)
+        self._highlight = None
+        self._mousePressed = False
+        self._state = InputState.StateNormal
+        self._axisX = None
+        self._axisY = None
+        self._axisZ = None
+        self._speedModifier = 20.0
+        self._aspectRatio = 0.0
+        self._axisXMinValue = 0.0
+        self._axisXMaxValue = 0.0
+        self._axisXMinRange = 0.0
+        self._axisZMinValue = 0.0
+        self._axisZMaxValue = 0.0
+        self._axisZMinRange = 0.0
+        self._areaMinValue = 0.0
+        self._areaMaxValue = 0.0
+
+        # Connect to the item selection signal from graph
+        graph.selectedElementChanged.connect(self.handleElementSelected)
+
+    def setAspectRatio(self, ratio):
+        self._aspectRatio = ratio
+
+    def setHighlightSeries(self, series):
+        self._highlight = series
+
+    def setDragSpeedModifier(self, modifier):
+        self._speedModifier = modifier
+
+    def setLimits(self, min, max, minRange):
+        self._areaMinValue = min
+        self._areaMaxValue = max
+        self._axisXMinValue = self._areaMinValue
+        self._axisXMaxValue = self._areaMaxValue
+        self._axisZMinValue = self._areaMinValue
+        self._axisZMaxValue = self._areaMaxValue
+        self._axisXMinRange = minRange
+        self._axisZMinRange = minRange
+
+    def setAxes(self, axisX, axisY, axisZ):
+        self._axisX = axisX
+        self._axisY = axisY
+        self._axisZ = axisZ
+
+    def mousePressEvent(self, event, mousePos):
+        if Qt.LeftButton == event.button():
+            self._highlight.setVisible(False)
+            self._mousePressed = True
+        super().mousePressEvent(event, mousePos)
+
+    def wheelEvent(self, event):
+        delta = float(event.angleDelta().y())
+
+        self._axisXMinValue += delta
+        self._axisXMaxValue -= delta
+        self._axisZMinValue += delta
+        self._axisZMaxValue -= delta
+        self.checkConstraints()
+
+        y = (self._axisXMaxValue - self._axisXMinValue) * self._aspectRatio
+
+        self._axisX.setRange(self._axisXMinValue, self._axisXMaxValue)
+        self._axisY.setRange(100.0, y)
+        self._axisZ.setRange(self._axisZMinValue, self._axisZMaxValue)
+
+    def mouseMoveEvent(self, event, mousePos):
+        # Check if we're trying to drag axis label
+        if self._mousePressed and self._state != InputState.StateNormal:
+            self.setPreviousInputPos(self.inputPosition())
+            self.setInputPosition(mousePos)
+            self.handleAxisDragging()
+        else:
+            super().mouseMoveEvent(event, mousePos)
+
+    def mouseReleaseEvent(self, event, mousePos):
+        super().mouseReleaseEvent(event, mousePos)
+        self._mousePressed = False
+        self._state = InputState.StateNormal
+
+    def handleElementSelected(self, type):
+        if type == QAbstract3DGraph.ElementAxisXLabel:
+            self._state = InputState.StateDraggingX
+        elif type == QAbstract3DGraph.ElementAxisZLabel:
+            self._state = InputState.StateDraggingZ
+        else:
+            self._state = InputState.StateNormal
+
+    def handleAxisDragging(self):
+        distance = 0.0
+
+        # Get scene orientation from active camera
+        xRotation = self.scene().cameraXRotation()
+
+        # Calculate directional drag multipliers based on rotation
+        xMulX = cos(degrees(xRotation))
+        xMulY = sin(degrees(xRotation))
+        zMulX = xMulY
+        zMulY = xMulX
+
+        # Get the drag amount
+        move = self.inputPosition() - self.previousInputPos()
+
+        # Adjust axes
+        if self._state == InputState.StateDraggingX:
+            distance = (move.x() * xMulX - move.y() * xMulY) * self._speedModifier
+            self._axisXMinValue -= distance
+            self._axisXMaxValue -= distance
+            if self._axisXMinValue < self._areaMinValue:
+                dist = self._axisXMaxValue - self._axisXMinValue
+                self._axisXMinValue = self._areaMinValue
+                self._axisXMaxValue = self._axisXMinValue + dist
+
+            if self._axisXMaxValue > self._areaMaxValue:
+                dist = self._axisXMaxValue - self._axisXMinValue
+                self._axisXMaxValue = self._areaMaxValue
+                self._axisXMinValue = self._axisXMaxValue - dist
+
+            self._axisX.setRange(self._axisXMinValue, self._axisXMaxValue)
+        elif self._state == InputState.StateDraggingZ:
+            distance = (move.x() * zMulX + move.y() * zMulY) * self._speedModifier
+            self._axisZMinValue += distance
+            self._axisZMaxValue += distance
+            if self._axisZMinValue < self._areaMinValue:
+                dist = self._axisZMaxValue - self._axisZMinValue
+                self._axisZMinValue = self._areaMinValue
+                self._axisZMaxValue = self._axisZMinValue + dist
+
+            if self._axisZMaxValue > self._areaMaxValue:
+                dist = self._axisZMaxValue - self._axisZMinValue
+                self._axisZMaxValue = self._areaMaxValue
+                self._axisZMinValue = self._axisZMaxValue - dist
+
+            self._axisZ.setRange(self._axisZMinValue, self._axisZMaxValue)
+
+    def checkConstraints(self):
+        if self._axisXMinValue < self._areaMinValue:
+            self._axisXMinValue = self._areaMinValue
+        if self._axisXMaxValue > self._areaMaxValue:
+            self._axisXMaxValue = self._areaMaxValue
+        # Don't allow too much zoom in
+        range = self._axisXMaxValue - self._axisXMinValue
+        if range < self._axisXMinRange:
+            adjust = (self._axisXMinRange - range) / 2.0
+            self._axisXMinValue -= adjust
+            self._axisXMaxValue += adjust
+
+        if self._axisZMinValue < self._areaMinValue:
+            self._axisZMinValue = self._areaMinValue
+        if self._axisZMaxValue > self._areaMaxValue:
+            self._axisZMaxValue = self._areaMaxValue
+        # Don't allow too much zoom in
+        range = self._axisZMaxValue - self._axisZMinValue
+        if range < self._axisZMinRange:
+            adjust = (self._axisZMinRange - range) / 2.0
+            self._axisZMinValue -= adjust
+            self._axisZMaxValue += adjust
diff --git a/examples/graphs/3d/widgetgallery/data/layer_1.png b/examples/graphs/3d/widgetgallery/data/layer_1.png
new file mode 100644 (file)
index 0000000..9138c71
Binary files /dev/null and b/examples/graphs/3d/widgetgallery/data/layer_1.png differ
diff --git a/examples/graphs/3d/widgetgallery/data/layer_2.png b/examples/graphs/3d/widgetgallery/data/layer_2.png
new file mode 100644 (file)
index 0000000..61631ae
Binary files /dev/null and b/examples/graphs/3d/widgetgallery/data/layer_2.png differ
diff --git a/examples/graphs/3d/widgetgallery/data/layer_3.png b/examples/graphs/3d/widgetgallery/data/layer_3.png
new file mode 100644 (file)
index 0000000..066ffbe
Binary files /dev/null and b/examples/graphs/3d/widgetgallery/data/layer_3.png differ
diff --git a/examples/graphs/3d/widgetgallery/data/license.txt b/examples/graphs/3d/widgetgallery/data/license.txt
new file mode 100644 (file)
index 0000000..749daf3
--- /dev/null
@@ -0,0 +1,77 @@
+License information regarding the data obtained from National Land Survey of
+Finland http://www.maanmittauslaitos.fi/en
+- topographic model from Elevation model 2 m (U4421B, U4421D, U4422A and
+  U4422C) 08/2014
+- map image extracted from Topographic map raster 1:50 000 (U442) 08/2014
+
+National Land Survey open data licence - version 1.0 - 1 May 2012
+
+1. General information
+
+The National Land Survey of Finland (hereinafter the Licensor), as the holder
+of the immaterial rights to the data, has granted on the terms mentioned below
+the right to use a copy (hereinafter data or dataset(s)) of the data (or a part
+of it).
+
+The Licensee is a natural or legal person who makes use of the data covered by
+this licence. The Licensee accepts the terms of this licence by receiving the
+dataset(s) covered by the licence.
+
+This Licence agreement does not create a co-operation or business relationship
+between the Licensee and the Licensor.
+
+2. Terms of the licence
+
+2.1. Right of use
+
+This licence grants a worldwide, free of charge and irrevocable parallel right
+of use to open data. According to the terms of the licence, data received by
+the Licensee can be freely:
+ - copied, distributed and published,
+ - modified and utilised commercially and non-commercially,
+ - inserted into other products and
+ - used as a part of a software application or service.
+
+2.2. Duties and responsibilities of the Licensee
+
+Through reasonable means suitable to the distribution medium or method which is
+used in conjunction with a product containing data or a service utilising data
+covered by this licence or while distributing data, the Licensee shall:
+ - mention the name of the Licensor, the name of the dataset(s) and the time
+   when the National Land Survey has delivered the dataset(s) (e.g.: contains
+   data from the National Land Survey of Finland Topographic Database 06/2012)
+ - provide a copy of this licence or a link to it, as well as
+ - require third parties to provide the same information when granting rights
+   to copies of dataset(s) or products and services containing such data and
+ - remove the name of the Licensor from the product or service, if required to
+   do so by the Licensor.
+
+The terms of this licence do not allow the Licensee to state in conjunction
+with the use of dataset(s) that the Licensor supports or recommends such use.
+
+2.3. Duties and responsibilities of the Licensor
+
+The Licensor shall ensure that
+ - the Licensor has the right to grant rights to the dataset(s) in accordance
+   with this licence.
+
+The data has been licensed "as is" and the Licensor
+ - shall not be held responsible for any errors or omissions in the data,
+   disclaims any warranty for the validity or up to date status of the data and
+   shall be free from liability for direct or consequential damages arising
+   from the use of data provided by the Licensor,
+ - and is not obligated to ensure the continuous availability of the data, nor
+   to announce in advance the interruption or cessation of availability, and
+   the Licensor shall be free from liability for direct or consequential
+   damages arising from any such interruption or cessation.
+
+3. Jurisdiction
+
+Finnish law shall apply to this licence.
+
+4. Changes to this licence
+
+The Licensor may at any time change the terms of the licence or apply a
+different licence to the data. The terms of this licence shall, however, still
+apply to such data that has been received prior to the change of the terms of
+the licence or the licence itself.
diff --git a/examples/graphs/3d/widgetgallery/data/maptexture.jpg b/examples/graphs/3d/widgetgallery/data/maptexture.jpg
new file mode 100644 (file)
index 0000000..ae5d66e
Binary files /dev/null and b/examples/graphs/3d/widgetgallery/data/maptexture.jpg differ
diff --git a/examples/graphs/3d/widgetgallery/data/narrowarrow.mesh b/examples/graphs/3d/widgetgallery/data/narrowarrow.mesh
new file mode 100644 (file)
index 0000000..288867b
Binary files /dev/null and b/examples/graphs/3d/widgetgallery/data/narrowarrow.mesh differ
diff --git a/examples/graphs/3d/widgetgallery/data/oilrig.mesh b/examples/graphs/3d/widgetgallery/data/oilrig.mesh
new file mode 100644 (file)
index 0000000..4a7baed
Binary files /dev/null and b/examples/graphs/3d/widgetgallery/data/oilrig.mesh differ
diff --git a/examples/graphs/3d/widgetgallery/data/pipe.mesh b/examples/graphs/3d/widgetgallery/data/pipe.mesh
new file mode 100644 (file)
index 0000000..984b6d4
Binary files /dev/null and b/examples/graphs/3d/widgetgallery/data/pipe.mesh differ
diff --git a/examples/graphs/3d/widgetgallery/data/raindata.txt b/examples/graphs/3d/widgetgallery/data/raindata.txt
new file mode 100644 (file)
index 0000000..d955892
--- /dev/null
@@ -0,0 +1,158 @@
+# Rainfall per month from 2010 to 2022 in Northern Finland (Oulu)
+# Format: year, month, rainfall
+2010,1, 0,
+2010,2, 3.4,
+2010,3, 52,
+2010,4, 33.8,
+2010,5, 45.6,
+2010,6, 43.8,
+2010,7, 104.6,
+2010,8, 105.4,
+2010,9, 107.2,
+2010,10,38.6,
+2010,11,17.8,
+2010,12,0,
+2011,1, 8.2,
+2011,2, 1.6,
+2011,3, 27.4,
+2011,4, 15.8,
+2011,5, 57.6,
+2011,6, 85.2,
+2011,7, 127,
+2011,8, 72.2,
+2011,9, 82.2,
+2011,10,62.4,
+2011,11,31.6,
+2011,12,53.8,
+2012,1, 0,
+2012,2, 5,
+2012,3, 32.4,
+2012,4, 57.6,
+2012,5, 71.4,
+2012,6, 60.8,
+2012,7, 109,
+2012,8, 43.6,
+2012,9, 79.4,
+2012,10,117.2,
+2012,11,59,
+2012,12,0.2,
+2013,1, 28,
+2013,2, 19,
+2013,3, 0,
+2013,4, 37.6,
+2013,5, 44.2,
+2013,6, 104.8,
+2013,7, 84.2,
+2013,8, 57.2,
+2013,9, 37.2,
+2013,10,64.6,
+2013,11,77.8,
+2013,12,92.8,
+2014,1, 23.8,
+2014,2, 23.6,
+2014,3, 15.4,
+2014,4, 13.2,
+2014,5, 36.4,
+2014,6, 26.4,
+2014,7, 95.8,
+2014,8, 81.8,
+2014,9, 13.8,
+2014,10,94.6,
+2014,11,44.6,
+2014,12,31,
+2015,1, 37.4,
+2015,2, 21,
+2015,3, 42,
+2015,4, 8.8,
+2015,5, 82.4,
+2015,6, 150,
+2015,7, 56.8,
+2015,8, 67.2,
+2015,9, 131.2,
+2015,10,38.4,
+2015,11,83.4,
+2015,12,47.8,
+2016,1, 12.4,
+2016,2, 34.8,
+2016,3, 29,
+2016,4, 40.4,
+2016,5, 32.4,
+2016,6, 80.2,
+2016,7, 102.6,
+2016,8, 95.6,
+2016,9, 40.2,
+2016,10,7.8,
+2016,11,39.6,
+2016,12,8.8,
+2017,1, 9.4,
+2017,2, 6.6,
+2017,3, 29,
+2017,4, 46.2,
+2017,5, 43.2,
+2017,6, 25.2,
+2017,7, 72.4,
+2017,8, 58.8,
+2017,9, 68.8,
+2017,10,45.8,
+2017,11,36.8,
+2017,12,29.6,
+2018,1, 19.8,
+2018,2, 0.8,
+2018,3, 4,
+2018,4, 23.2,
+2018,5, 13.2,
+2018,6, 62.8,
+2018,7, 33,
+2018,8, 96.6,
+2018,9, 72.6,
+2018,10,48.8,
+2018,11,31.8,
+2018,12,12.8,
+2019,1, 0.2,
+2019,2, 24.8,
+2019,3, 32,
+2019,4, 8.8,
+2019,5, 71.4,
+2019,6, 65.8,
+2019,7, 17.6,
+2019,8, 90,
+2019,9, 50,
+2019,10,77,
+2019,11,27,
+2019,12,43.2,
+2020,1, 28.8,
+2020,2, 45,
+2020,3, 18.6,
+2020,4, 13,
+2020,5, 30.8,
+2020,6, 21.4,
+2020,7, 163.6,
+2020,8, 12,
+2020,9, 102.4,
+2020,10,133.2,
+2020,11,69.8,
+2020,12,40.6,
+2021,1, 0.4,
+2021,2, 21.6,
+2021,3, 24,
+2021,4, 51.4,
+2021,5, 76.4,
+2021,6, 29.2,
+2021,7, 36.4,
+2021,8, 116,
+2021,9, 72.4,
+2021,10,93.4,
+2021,11,21,
+2021,12,10.2,
+2022,1, 8.6,
+2022,2, 6.6,
+2022,3, 5.2,
+2022,4, 15.2,
+2022,5, 37.6,
+2022,6, 45,
+2022,7, 67.4,
+2022,8, 161.6,
+2022,9, 22.8,
+2022,10,75.2,
+2022,11,21.8,
+2022,12,0.2
diff --git a/examples/graphs/3d/widgetgallery/data/refinery.mesh b/examples/graphs/3d/widgetgallery/data/refinery.mesh
new file mode 100644 (file)
index 0000000..a7e2493
Binary files /dev/null and b/examples/graphs/3d/widgetgallery/data/refinery.mesh differ
diff --git a/examples/graphs/3d/widgetgallery/data/topography.png b/examples/graphs/3d/widgetgallery/data/topography.png
new file mode 100644 (file)
index 0000000..9349cdb
Binary files /dev/null and b/examples/graphs/3d/widgetgallery/data/topography.png differ
diff --git a/examples/graphs/3d/widgetgallery/doc/widgetgallery.rst b/examples/graphs/3d/widgetgallery/doc/widgetgallery.rst
new file mode 100644 (file)
index 0000000..1470001
--- /dev/null
@@ -0,0 +1,11 @@
+Widget Gallery
+==============
+
+
+Widget Gallery demonstrates all three graph types and some of their special
+features. The graphs have their own tabs in the application.
+
+
+.. image:: widgetgallery.webp
+   :width: 400
+   :alt: Widget Screenshot
diff --git a/examples/graphs/3d/widgetgallery/doc/widgetgallery.webp b/examples/graphs/3d/widgetgallery/doc/widgetgallery.webp
new file mode 100644 (file)
index 0000000..eb57672
Binary files /dev/null and b/examples/graphs/3d/widgetgallery/doc/widgetgallery.webp differ
diff --git a/examples/graphs/3d/widgetgallery/graphmodifier.py b/examples/graphs/3d/widgetgallery/graphmodifier.py
new file mode 100644 (file)
index 0000000..2eaafa7
--- /dev/null
@@ -0,0 +1,391 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+from math import atan, degrees
+import numpy as np
+
+from PySide6.QtCore import QObject, QPropertyAnimation, Signal, Slot
+from PySide6.QtGui import QFont, QVector3D
+from PySide6.QtGraphs import (QAbstract3DGraph, QAbstract3DSeries,
+                              QBarDataItem, QBar3DSeries, QCategory3DAxis,
+                              QValue3DAxis, Q3DTheme)
+
+from rainfalldata import RainfallData
+
+# Set up data
+TEMP_OULU = np.array([
+    [-7.4, -2.4, 0.0, 3.0, 8.2, 11.6, 14.7, 15.4, 11.4, 4.2, 2.1, -2.3],  # 2015
+    [-13.4, -3.9, -1.8, 3.1, 10.6, 13.7, 17.8, 13.6, 10.7, 3.5, -3.1, -4.2],  # 2016
+    [-5.7, -6.7, -3.0, -0.1, 4.7, 12.4, 16.1, 14.1, 9.4, 3.0, -0.3, -3.2],  # 2017
+    [-6.4, -11.9, -7.4, 1.9, 11.4, 12.4, 21.5, 16.1, 11.0, 4.4, 2.1, -4.1],  # 2018
+    [-11.7, -6.1, -2.4, 3.9, 7.2, 14.5, 15.6, 14.4, 8.5, 2.0, -3.0, -1.5],  # 2019
+    [-2.1, -3.4, -1.8, 0.6, 7.0, 17.1, 15.6, 15.4, 11.1, 5.6, 1.9, -1.7],  # 2020
+    [-9.6, -11.6, -3.2, 2.4, 7.8, 17.3, 19.4, 14.2, 8.0, 5.2, -2.2, -8.6],  # 2021
+    [-7.3, -6.4, -1.8, 1.3, 8.1, 15.5, 17.6, 17.6, 9.1, 5.4, -1.5, -4.4]],  # 2022
+    np.float64)
+
+
+TEMP_HELSINKI = np.array([
+    [-2.0, -0.1, 1.8, 5.1, 9.7, 13.7, 16.3, 17.3, 12.7, 5.4, 4.6, 2.1],  # 2015
+    [-10.3, -0.6, 0.0, 4.9, 14.3, 15.7, 17.7, 16.0, 12.7, 4.6, -1.0, -0.9],  # 2016
+    [-2.9, -3.3, 0.7, 2.3, 9.9, 13.8, 16.1, 15.9, 11.4, 5.0, 2.7, 0.7],  # 2017
+    [-2.2, -8.4, -4.7, 5.0, 15.3, 15.8, 21.2, 18.2, 13.3, 6.7, 2.8, -2.0],  # 2018
+    [-6.2, -0.5, -0.3, 6.8, 10.6, 17.9, 17.5, 16.8, 11.3, 5.2, 1.8, 1.4],  # 2019
+    [1.9, 0.5, 1.7, 4.5, 9.5, 18.4, 16.5, 16.8, 13.0, 8.2, 4.4, 0.9],  # 2020
+    [-4.7, -8.1, -0.9, 4.5, 10.4, 19.2, 20.9, 15.4, 9.5, 8.0, 1.5, -6.7],  # 2021
+    [-3.3, -2.2, -0.2, 3.3, 9.6, 16.9, 18.1, 18.9, 9.2, 7.6, 2.3, -3.4]],  # 2022
+    np.float64)
+
+
+class GraphModifier(QObject):
+
+    shadowQualityChanged = Signal(int)
+    backgroundEnabledChanged = Signal(bool)
+    gridEnabledChanged = Signal(bool)
+    fontChanged = Signal(QFont)
+    fontSizeChanged = Signal(int)
+
+    def __init__(self, bargraph, parent):
+        super().__init__(parent)
+        self._graph = bargraph
+        self._temperatureAxis = QValue3DAxis()
+        self._yearAxis = QCategory3DAxis()
+        self._monthAxis = QCategory3DAxis()
+        self._primarySeries = QBar3DSeries()
+        self._secondarySeries = QBar3DSeries()
+        self._celsiusString = "°C"
+
+        self._xRotation = float(0)
+        self._yRotation = float(0)
+        self._fontSize = 30
+        self._segments = 4
+        self._subSegments = 3
+        self._minval = float(-20)
+        self._maxval = float(20)
+        self._barMesh = QAbstract3DSeries.Mesh.BevelBar
+        self._smooth = False
+        self._animationCameraX = QPropertyAnimation()
+        self._animationCameraY = QPropertyAnimation()
+        self._animationCameraZoom = QPropertyAnimation()
+        self._animationCameraTarget = QPropertyAnimation()
+        self._defaultAngleX = float(0)
+        self._defaultAngleY = float(0)
+        self._defaultZoom = float(0)
+        self._defaultTarget = []
+        self._customData = None
+
+        self._graph.setShadowQuality(QAbstract3DGraph.ShadowQuality.SoftMedium)
+        theme = self._graph.activeTheme()
+        theme.setBackgroundEnabled(False)
+        theme.setFont(QFont("Times New Roman", self._fontSize))
+        theme.setLabelBackgroundEnabled(True)
+        self._graph.setMultiSeriesUniform(True)
+
+        self._months = ["January", "February", "March", "April", "May", "June",
+                        "July", "August", "September", "October", "November",
+                        "December"]
+        self._years = ["2015", "2016", "2017", "2018", "2019", "2020",
+                       "2021", "2022"]
+
+        self._temperatureAxis.setTitle("Average temperature")
+        self._temperatureAxis.setSegmentCount(self._segments)
+        self._temperatureAxis.setSubSegmentCount(self._subSegments)
+        self._temperatureAxis.setRange(self._minval, self._maxval)
+        self._temperatureAxis.setLabelFormat("%.1f " + self._celsiusString)
+        self._temperatureAxis.setLabelAutoRotation(30.0)
+        self._temperatureAxis.setTitleVisible(True)
+
+        self._yearAxis.setTitle("Year")
+        self._yearAxis.setLabelAutoRotation(30.0)
+        self._yearAxis.setTitleVisible(True)
+        self._monthAxis.setTitle("Month")
+        self._monthAxis.setLabelAutoRotation(30.0)
+        self._monthAxis.setTitleVisible(True)
+
+        self._graph.setValueAxis(self._temperatureAxis)
+        self._graph.setRowAxis(self._yearAxis)
+        self._graph.setColumnAxis(self._monthAxis)
+
+        format = "Oulu - @colLabel @rowLabel: @valueLabel"
+        self._primarySeries.setItemLabelFormat(format)
+        self._primarySeries.setMesh(QAbstract3DSeries.Mesh.BevelBar)
+        self._primarySeries.setMeshSmooth(False)
+
+        format = "Helsinki - @colLabel @rowLabel: @valueLabel"
+        self._secondarySeries.setItemLabelFormat(format)
+        self._secondarySeries.setMesh(QAbstract3DSeries.Mesh.BevelBar)
+        self._secondarySeries.setMeshSmooth(False)
+        self._secondarySeries.setVisible(False)
+
+        self._graph.addSeries(self._primarySeries)
+        self._graph.addSeries(self._secondarySeries)
+
+        self.changePresetCamera()
+
+        self.resetTemperatureData()
+
+        # Set up property animations for zooming to the selected bar
+        self._defaultAngleX = self._graph.cameraXRotation()
+        self._defaultAngleY = self._graph.cameraYRotation()
+        self._defaultZoom = self._graph.cameraZoomLevel()
+        self._defaultTarget = self._graph.cameraTargetPosition()
+
+        self._animationCameraX.setTargetObject(self._graph)
+        self._animationCameraY.setTargetObject(self._graph)
+        self._animationCameraZoom.setTargetObject(self._graph)
+        self._animationCameraTarget.setTargetObject(self._graph)
+
+        self._animationCameraX.setPropertyName(b"cameraXRotation")
+        self._animationCameraY.setPropertyName(b"cameraYRotation")
+        self._animationCameraZoom.setPropertyName(b"cameraZoomLevel")
+        self._animationCameraTarget.setPropertyName(b"cameraTargetPosition")
+
+        duration = 1700
+        self._animationCameraX.setDuration(duration)
+        self._animationCameraY.setDuration(duration)
+        self._animationCameraZoom.setDuration(duration)
+        self._animationCameraTarget.setDuration(duration)
+
+        # The zoom always first zooms out above the graph and then zooms in
+        zoomOutFraction = 0.3
+        self._animationCameraX.setKeyValueAt(zoomOutFraction, 0.0)
+        self._animationCameraY.setKeyValueAt(zoomOutFraction, 90.0)
+        self._animationCameraZoom.setKeyValueAt(zoomOutFraction, 50.0)
+        self._animationCameraTarget.setKeyValueAt(zoomOutFraction,
+                                                  QVector3D(0, 0, 0))
+        self._customData = RainfallData()
+
+    def resetTemperatureData(self):
+        # Create data arrays
+        dataSet = []
+        dataSet2 = []
+
+        for year in range(0, len(self._years)):
+            # Create a data row
+            dataRow = []
+            dataRow2 = []
+            for month in range(0, len(self._months)):
+                # Add data to the row
+                item = QBarDataItem()
+                item.setValue(TEMP_OULU[year][month])
+                dataRow.append(item)
+                item = QBarDataItem()
+                item.setValue(TEMP_HELSINKI[year][month])
+                dataRow2.append(item)
+
+            # Add the row to the set
+            dataSet.append(dataRow)
+            dataSet2.append(dataRow2)
+
+        # Add data to the data proxy (the data proxy assumes ownership of it)
+        self._primarySeries.dataProxy().resetArray(dataSet, self._years, self._months)
+        self._secondarySeries.dataProxy().resetArray(dataSet2, self._years, self._months)
+
+    @Slot(int)
+    def changeRange(self, range):
+        if range >= len(self._years):
+            self._yearAxis.setRange(0, len(self._years) - 1)
+        else:
+            self._yearAxis.setRange(range, range)
+
+    @Slot(int)
+    def changeStyle(self, style):
+        comboBox = self.sender()
+        if comboBox:
+            self._barMesh = comboBox.itemData(style)
+            self._primarySeries.setMesh(self._barMesh)
+            self._secondarySeries.setMesh(self._barMesh)
+            self._customData.customSeries().setMesh(self._barMesh)
+
+    def changePresetCamera(self):
+        self._animationCameraX.stop()
+        self._animationCameraY.stop()
+        self._animationCameraZoom.stop()
+        self._animationCameraTarget.stop()
+
+        # Restore camera target in case animation has changed it
+        self._graph.setCameraTargetPosition(QVector3D(0.0, 0.0, 0.0))
+
+        self._preset = QAbstract3DGraph.CameraPreset.Front.value
+
+        self._graph.setCameraPreset(QAbstract3DGraph.CameraPreset(self._preset))
+
+        self._preset += 1
+        if self._preset > QAbstract3DGraph.CameraPreset.DirectlyBelow.value:
+            self._preset = QAbstract3DGraph.CameraPreset.FrontLow.value
+
+    @Slot(int)
+    def changeTheme(self, theme):
+        currentTheme = self._graph.activeTheme()
+        currentTheme.setType(Q3DTheme.Theme(theme))
+        self.backgroundEnabledChanged.emit(currentTheme.isBackgroundEnabled())
+        self.gridEnabledChanged.emit(currentTheme.isGridEnabled())
+        self.fontChanged.emit(currentTheme.font())
+        self.fontSizeChanged.emit(currentTheme.font().pointSize())
+
+    def changeLabelBackground(self):
+        theme = self._graph.activeTheme()
+        theme.setLabelBackgroundEnabled(not theme.isLabelBackgroundEnabled())
+
+    @Slot(int)
+    def changeSelectionMode(self, selectionMode):
+        comboBox = self.sender()
+        if comboBox:
+            flags = comboBox.itemData(selectionMode)
+            self._graph.setSelectionMode(QAbstract3DGraph.SelectionFlags(flags))
+
+    def changeFont(self, font):
+        newFont = font
+        self._graph.activeTheme().setFont(newFont)
+
+    def changeFontSize(self, fontsize):
+        self._fontSize = fontsize
+        font = self._graph.activeTheme().font()
+        font.setPointSize(self._fontSize)
+        self._graph.activeTheme().setFont(font)
+
+    @Slot(QAbstract3DGraph.ShadowQuality)
+    def shadowQualityUpdatedByVisual(self, sq):
+        # Updates the UI component to show correct shadow quality
+        self.shadowQualityChanged.emit(sq.value)
+
+    @Slot(int)
+    def changeLabelRotation(self, rotation):
+        self._temperatureAxis.setLabelAutoRotation(float(rotation))
+        self._monthAxis.setLabelAutoRotation(float(rotation))
+        self._yearAxis.setLabelAutoRotation(float(rotation))
+
+    @Slot(bool)
+    def setAxisTitleVisibility(self, enabled):
+        self._temperatureAxis.setTitleVisible(enabled)
+        self._monthAxis.setTitleVisible(enabled)
+        self._yearAxis.setTitleVisible(enabled)
+
+    @Slot(bool)
+    def setAxisTitleFixed(self, enabled):
+        self._temperatureAxis.setTitleFixed(enabled)
+        self._monthAxis.setTitleFixed(enabled)
+        self._yearAxis.setTitleFixed(enabled)
+
+    @Slot()
+    def zoomToSelectedBar(self):
+        self._animationCameraX.stop()
+        self._animationCameraY.stop()
+        self._animationCameraZoom.stop()
+        self._animationCameraTarget.stop()
+
+        currentX = self._graph.cameraXRotation()
+        currentY = self._graph.cameraYRotation()
+        currentZoom = self._graph.cameraZoomLevel()
+        currentTarget = self._graph.cameraTargetPosition()
+
+        self._animationCameraX.setStartValue(currentX)
+        self._animationCameraY.setStartValue(currentY)
+        self._animationCameraZoom.setStartValue(currentZoom)
+        self._animationCameraTarget.setStartValue(currentTarget)
+
+        selectedBar = (self._graph.selectedSeries().selectedBar()
+                       if self._graph.selectedSeries()
+                       else QBar3DSeries.invalidSelectionPosition())
+
+        if selectedBar != QBar3DSeries.invalidSelectionPosition():
+            # Normalize selected bar position within axis range to determine
+            # target coordinates
+            endTarget = QVector3D()
+            xMin = self._graph.columnAxis().min()
+            xRange = self._graph.columnAxis().max() - xMin
+            zMin = self._graph.rowAxis().min()
+            zRange = self._graph.rowAxis().max() - zMin
+            endTarget.setX((selectedBar.y() - xMin) / xRange * 2.0 - 1.0)
+            endTarget.setZ((selectedBar.x() - zMin) / zRange * 2.0 - 1.0)
+
+            # Rotate the camera so that it always points approximately to the
+            # graph center
+            endAngleX = 90.0 - degrees(atan(float(endTarget.z() / endTarget.x())))
+            if endTarget.x() > 0.0:
+                endAngleX -= 180.0
+            proxy = self._graph.selectedSeries().dataProxy()
+            barValue = proxy.itemAt(selectedBar.x(), selectedBar.y()).value()
+            endAngleY = 30.0 if barValue >= 0.0 else -30.0
+            if self._graph.valueAxis().reversed():
+                endAngleY *= -1.0
+
+            self._animationCameraX.setEndValue(float(endAngleX))
+            self._animationCameraY.setEndValue(endAngleY)
+            self._animationCameraZoom.setEndValue(250)
+            self._animationCameraTarget.setEndValue(endTarget)
+        else:
+            # No selected bar, so return to the default view
+            self._animationCameraX.setEndValue(self._defaultAngleX)
+            self._animationCameraY.setEndValue(self._defaultAngleY)
+            self._animationCameraZoom.setEndValue(self._defaultZoom)
+            self._animationCameraTarget.setEndValue(self._defaultTarget)
+
+        self._animationCameraX.start()
+        self._animationCameraY.start()
+        self._animationCameraZoom.start()
+        self._animationCameraTarget.start()
+
+    @Slot(bool)
+    def setDataModeToWeather(self, enabled):
+        if enabled:
+            self.changeDataMode(False)
+
+    @Slot(bool)
+    def setDataModeToCustom(self, enabled):
+        if enabled:
+            self.changeDataMode(True)
+
+    def changeShadowQuality(self, quality):
+        sq = QAbstract3DGraph.ShadowQuality(quality)
+        self._graph.setShadowQuality(sq)
+        self.shadowQualityChanged.emit(quality)
+
+    def rotateX(self, rotation):
+        self._xRotation = rotation
+        camera = self._graph.scene().activeCamera()
+        camera.setCameraPosition(self._xRotation, self._yRotation)
+
+    def rotateY(self, rotation):
+        self._yRotation = rotation
+        camera = self._graph.scene().activeCamera()
+        camera.setCameraPosition(self._xRotation, self._yRotation)
+
+    def setBackgroundEnabled(self, enabled):
+        self._graph.activeTheme().setBackgroundEnabled(bool(enabled))
+
+    def setGridEnabled(self, enabled):
+        self._graph.activeTheme().setGridEnabled(bool(enabled))
+
+    def setSmoothBars(self, smooth):
+        self._smooth = bool(smooth)
+        self._primarySeries.setMeshSmooth(self._smooth)
+        self._secondarySeries.setMeshSmooth(self._smooth)
+        self._customData.customSeries().setMeshSmooth(self._smooth)
+
+    def setSeriesVisibility(self, enabled):
+        self._secondarySeries.setVisible(bool(enabled))
+
+    def setReverseValueAxis(self, enabled):
+        self._graph.valueAxis().setReversed(enabled)
+
+    def setReflection(self, enabled):
+        self._graph.setReflection(enabled)
+
+    def changeDataMode(self, customData):
+        # Change between weather data and data from custom proxy
+        if customData:
+            self._graph.removeSeries(self._primarySeries)
+            self._graph.removeSeries(self._secondarySeries)
+            self._graph.addSeries(self._customData.customSeries())
+            self._graph.setValueAxis(self._customData.valueAxis())
+            self._graph.setRowAxis(self._customData.rowAxis())
+            self._graph.setColumnAxis(self._customData.colAxis())
+        else:
+            self._graph.removeSeries(self._customData.customSeries())
+            self._graph.addSeries(self._primarySeries)
+            self._graph.addSeries(self._secondarySeries)
+            self._graph.setValueAxis(self._temperatureAxis)
+            self._graph.setRowAxis(self._yearAxis)
+            self._graph.setColumnAxis(self._monthAxis)
diff --git a/examples/graphs/3d/widgetgallery/highlightseries.py b/examples/graphs/3d/widgetgallery/highlightseries.py
new file mode 100644 (file)
index 0000000..8c7b916
--- /dev/null
@@ -0,0 +1,94 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtCore import QPoint, Qt, Slot
+from PySide6.QtGui import QLinearGradient, QVector3D
+from PySide6.QtGraphs import (QSurface3DSeries, QSurfaceDataItem, Q3DTheme)
+
+
+DARK_RED_POS = 1.0
+RED_POS = 0.8
+YELLOW_POS = 0.6
+GREEN_POS = 0.4
+DARK_GREEN_POS = 0.2
+
+
+class HighlightSeries(QSurface3DSeries):
+
+    def __init__(self):
+        super().__init__()
+        self._width = 100
+        self._height = 100
+        self._srcWidth = 0
+        self._srcHeight = 0
+        self._position = {}
+        self._topographicSeries = None
+        self._minHeight = 0.0
+        self.setDrawMode(QSurface3DSeries.DrawSurface)
+        self.setFlatShadingEnabled(True)
+        self.setVisible(False)
+
+    def setTopographicSeries(self, series):
+        self._topographicSeries = series
+        array = self._topographicSeries.dataProxy().array()
+        self._srcWidth = len(array[0])
+        self._srcHeight = len(array)
+        self._topographicSeries.selectedPointChanged.connect(self.handlePositionChange)
+
+    def setMinHeight(self, height):
+        self. m_minHeight = height
+
+    @Slot(QPoint)
+    def handlePositionChange(self, position):
+        self._position = position
+
+        if position == self.invalidSelectionPosition():
+            self.setVisible(False)
+            return
+
+        halfWidth = self._width / 2
+        halfHeight = self._height / 2
+
+        startX = position.y() - halfWidth
+        if startX < 0:
+            startX = 0
+        endX = position.y() + halfWidth
+        if endX > (self._srcWidth - 1):
+            endX = self._srcWidth - 1
+        startZ = position.x() - halfHeight
+        if startZ < 0:
+            startZ = 0
+        endZ = position.x() + halfHeight
+        if endZ > (self._srcHeight - 1):
+            endZ = self._srcHeight - 1
+
+        srcProxy = self._topographicSeries.dataProxy()
+        srcArray = srcProxy.array()
+
+        dataArray = []
+        for i in range(int(startZ), int(endZ)):
+            newRow = []
+            srcRow = srcArray[i]
+            for j in range(startX, endX):
+                pos = srcRow.at(j).position()
+                pos.setY(pos.y() + 0.1)
+                item = QSurfaceDataItem(QVector3D(pos))
+                newRow.append(item)
+            dataArray.append(newRow)
+        self.dataProxy().resetArray(dataArray)
+        self.setVisible(True)
+
+    @Slot(float)
+    def handleGradientChange(self, value):
+        ratio = self._minHeight / value
+
+        gr = QLinearGradient()
+        gr.setColorAt(0.0, Qt.black)
+        gr.setColorAt(DARK_GREEN_POS * ratio, Qt.darkGreen)
+        gr.setColorAt(GREEN_POS * ratio, Qt.green)
+        gr.setColorAt(YELLOW_POS * ratio, Qt.yellow)
+        gr.setColorAt(RED_POS * ratio, Qt.red)
+        gr.setColorAt(DARK_RED_POS * ratio, Qt.darkRed)
+
+        self.setBaseGradient(gr)
+        self.setColorStyle(Q3DTheme.ColorStyle.RangeGradient)
diff --git a/examples/graphs/3d/widgetgallery/main.py b/examples/graphs/3d/widgetgallery/main.py
new file mode 100644 (file)
index 0000000..7bb2238
--- /dev/null
@@ -0,0 +1,41 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+"""PySide6 port of the Qt Graphs widgetgallery example from Qt v6.x"""
+
+import sys
+
+from PySide6.QtCore import QSize
+from PySide6.QtWidgets import QApplication, QTabWidget
+
+from bargraph import BarGraph
+from scattergraph import ScatterGraph
+from surfacegraph import SurfaceGraph
+
+
+if __name__ == "__main__":
+    app = QApplication(sys.argv)
+
+    # Create a tab widget for creating own tabs for Q3DBars, Q3DScatter, and Q3DSurface
+    tabWidget = QTabWidget()
+    tabWidget.setWindowTitle("Widget Gallery")
+
+    screen_size = tabWidget.screen().size()
+    minimum_graph_size = QSize(screen_size.width() / 2, screen_size.height() / 1.75)
+
+    # Create bar graph
+    bars = BarGraph(minimum_graph_size, screen_size)
+    # Create scatter graph
+    scatter = ScatterGraph(minimum_graph_size, screen_size)
+    # Create surface graph
+    surface = SurfaceGraph(minimum_graph_size, screen_size)
+
+    # Add bars widget
+    tabWidget.addTab(bars.barsWidget(), "Bar Graph")
+    # Add scatter widget
+    tabWidget.addTab(scatter.scatterWidget(), "Scatter Graph")
+    # Add surface widget
+    tabWidget.addTab(surface.surfaceWidget(), "Surface Graph")
+
+    tabWidget.show()
+    sys.exit(app.exec())
diff --git a/examples/graphs/3d/widgetgallery/rainfalldata.py b/examples/graphs/3d/widgetgallery/rainfalldata.py
new file mode 100644 (file)
index 0000000..d74f45a
--- /dev/null
@@ -0,0 +1,125 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import sys
+
+from pathlib import Path
+
+from PySide6.QtCore import QFile, QIODevice, QObject
+from PySide6.QtGraphs import (QBar3DSeries, QCategory3DAxis, QValue3DAxis)
+
+from variantbardataproxy import VariantBarDataProxy
+from variantbardatamapping import VariantBarDataMapping
+from variantdataset import VariantDataSet
+
+
+MONTHS = ["January", "February", "March", "April",
+          "May", "June", "July", "August", "September", "October",
+          "November", "December"]
+
+
+class RainfallData(QObject):
+
+    def __init__(self):
+        super().__init__()
+        self._columnCount = 0
+        self._rowCount = 0
+        self._years = []
+        self._numericMonths = []
+        self._proxy = VariantBarDataProxy()
+        self._mapping = None
+        self._dataSet = None
+        self._series = QBar3DSeries()
+        self._valueAxis = QValue3DAxis()
+        self._rowAxis = QCategory3DAxis()
+        self._colAxis = QCategory3DAxis()
+
+        # In data file the months are in numeric format, so create custom list
+        for i in range(1, 13):
+            self._numericMonths.append(str(i))
+
+        self._columnCount = len(self._numericMonths)
+
+        self.updateYearsList(2010, 2022)
+
+        # Create proxy and series
+        self._proxy = VariantBarDataProxy()
+        self._series = QBar3DSeries(self._proxy)
+
+        self._series.setItemLabelFormat("%.1f mm")
+
+        # Create the axes
+        self._rowAxis = QCategory3DAxis(self)
+        self._colAxis = QCategory3DAxis(self)
+        self._valueAxis = QValue3DAxis(self)
+        self._rowAxis.setAutoAdjustRange(True)
+        self._colAxis.setAutoAdjustRange(True)
+        self._valueAxis.setAutoAdjustRange(True)
+
+        # Set axis labels and titles
+        self._rowAxis.setTitle("Year")
+        self._colAxis.setTitle("Month")
+        self._valueAxis.setTitle("rainfall (mm)")
+        self._valueAxis.setSegmentCount(5)
+        self._rowAxis.setLabels(self._years)
+        self._colAxis.setLabels(MONTHS)
+        self._rowAxis.setTitleVisible(True)
+        self._colAxis.setTitleVisible(True)
+        self._valueAxis.setTitleVisible(True)
+
+        self.addDataSet()
+
+    def customSeries(self):
+        return self._series
+
+    def valueAxis(self):
+        return self._valueAxis
+
+    def rowAxis(self):
+        return self._rowAxis
+
+    def colAxis(self):
+        return self._colAxis
+
+    def updateYearsList(self, start, end):
+        self._years.clear()
+        for i in range(start, end + 1):
+            self._years.append(str(i))
+        self._rowCount = len(self._years)
+
+    def addDataSet(self):
+        # Create a new variant data set and data item list
+        self._dataSet = VariantDataSet()
+        itemList = []
+
+        # Read data from a data file into the data item list
+        file_path = Path(__file__).resolve().parent / "data" / "raindata.txt"
+        dataFile = QFile(file_path)
+        if dataFile.open(QIODevice.ReadOnly | QIODevice.Text):
+            data = dataFile.readAll().data().decode("utf8")
+            for line in data.split("\n"):
+                if line and not line.startswith("#"):  # Ignore comments
+                    tokens = line.split(",")
+                    # Each line has three data items: Year, month, and
+                    # rainfall value
+                    if len(tokens) >= 3:
+                        # Store year and month as strings, and rainfall value
+                        # as double into a variant data item and add the item to
+                        # the item list.
+                        newItem = []
+                        newItem.append(tokens[0].strip())
+                        newItem.append(tokens[1].strip())
+                        newItem.append(float(tokens[2].strip()))
+                        itemList.append(newItem)
+        else:
+            print("Unable to open data file:", dataFile.fileName(),
+                  file=sys.stderr)
+
+        # Add items to the data set and set it to the proxy
+        self._dataSet.addItems(itemList)
+        self._proxy.setDataSet(self._dataSet)
+
+        # Create new mapping for the data and set it to the proxy
+        self._mapping = VariantBarDataMapping(0, 1, 2,
+                                              self._years, self._numericMonths)
+        self._proxy.setMapping(self._mapping)
diff --git a/examples/graphs/3d/widgetgallery/scatterdatamodifier.py b/examples/graphs/3d/widgetgallery/scatterdatamodifier.py
new file mode 100644 (file)
index 0000000..15064b4
--- /dev/null
@@ -0,0 +1,149 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from math import cos, degrees, sqrt
+
+from PySide6.QtCore import QObject, Signal, Slot, Qt
+from PySide6.QtGui import QVector3D
+from PySide6.QtGraphs import (QAbstract3DGraph, QAbstract3DSeries,
+                              QScatterDataItem, QScatterDataProxy,
+                              QScatter3DSeries, Q3DTheme)
+
+from axesinputhandler import AxesInputHandler
+
+
+NUMBER_OF_ITEMS = 10000
+CURVE_DIVIDER = 7.5
+LOWER_NUMBER_OF_ITEMS = 900
+LOWER_CURVE_DIVIDER = 0.75
+
+
+class ScatterDataModifier(QObject):
+
+    backgroundEnabledChanged = Signal(bool)
+    gridEnabledChanged = Signal(bool)
+    shadowQualityChanged = Signal(int)
+
+    def __init__(self, scatter, parent):
+        super().__init__(parent)
+
+        self._graph = scatter
+
+        self._style = QAbstract3DSeries.Mesh.Sphere
+        self._smooth = True
+        self._inputHandler = AxesInputHandler(scatter)
+        self._autoAdjust = True
+        self._itemCount = LOWER_NUMBER_OF_ITEMS
+        self._CURVE_DIVIDER = LOWER_CURVE_DIVIDER
+        self._inputHandler = AxesInputHandler(scatter)
+
+        self._graph.activeTheme().setType(Q3DTheme.Theme.StoneMoss)
+        self._graph.setShadowQuality(QAbstract3DGraph.ShadowQuality.SoftHigh)
+        self._graph.setCameraPreset(QAbstract3DGraph.CameraPreset.Front)
+        self._graph.setCameraZoomLevel(80.0)
+
+        self._proxy = QScatterDataProxy()
+        self._series = QScatter3DSeries(self._proxy)
+        self._series.setItemLabelFormat("@xTitle: @xLabel @yTitle: @yLabel @zTitle: @zLabel")
+        self._series.setMeshSmooth(self._smooth)
+        self._graph.addSeries(self._series)
+        self._preset = QAbstract3DGraph.CameraPreset.FrontLow.value
+
+        # Give ownership of the handler to the graph and make it the active
+        # handler
+        self._graph.setActiveInputHandler(self._inputHandler)
+
+        # Give our axes to the input handler
+        self._inputHandler.setAxes(self._graph.axisX(), self._graph.axisZ(),
+                                   self._graph.axisY())
+
+        self.addData()
+
+    def addData(self):
+        # Configure the axes according to the data
+        self._graph.axisX().setTitle("X")
+        self._graph.axisY().setTitle("Y")
+        self._graph.axisZ().setTitle("Z")
+
+        dataArray = []
+        limit = int(sqrt(self._itemCount) / 2.0)
+        for i in range(-limit, limit):
+            for j in range(-limit, limit):
+                x = float(i) + 0.5
+                y = cos(degrees(float(i * j) / self._CURVE_DIVIDER))
+                z = float(j) + 0.5
+                dataArray.append(QScatterDataItem(QVector3D(x, y, z)))
+
+        self._graph.seriesList()[0].dataProxy().resetArray(dataArray)
+
+    @Slot(int)
+    def changeStyle(self, style):
+        comboBox = self.sender()
+        if comboBox:
+            self._style = comboBox.itemData(style)
+            if self._graph.seriesList():
+                self._graph.seriesList()[0].setMesh(self._style)
+
+    @Slot(int)
+    def setSmoothDots(self, smooth):
+        self._smooth = smooth == Qt.Checked.value
+        series = self._graph.seriesList()[0]
+        series.setMeshSmooth(self._smooth)
+
+    @Slot(int)
+    def changeTheme(self, theme):
+        currentTheme = self._graph.activeTheme()
+        currentTheme.setType(Q3DTheme.Theme(theme))
+        self.backgroundEnabledChanged.emit(currentTheme.isBackgroundEnabled())
+        self.gridEnabledChanged.emit(currentTheme.isGridEnabled())
+
+    @Slot()
+    def changePresetCamera(self):
+        camera = self._graph.scene().activeCamera()
+        camera.setCameraPreset(QAbstract3DGraph.CameraPreset(self._preset))
+
+        self._preset += 1
+        if self._preset > QAbstract3DGraph.CameraPreset.DirectlyBelow.value:
+            self._preset = QAbstract3DGraph.CameraPreset.FrontLow.value
+
+    @Slot(QAbstract3DGraph.ShadowQuality)
+    def shadowQualityUpdatedByVisual(self, sq):
+        self.shadowQualityChanged.emit(sq.value)
+
+    @Slot(int)
+    def changeShadowQuality(self, quality):
+        sq = QAbstract3DGraph.ShadowQuality(quality)
+        self._graph.setShadowQuality(sq)
+
+    @Slot(int)
+    def setBackgroundEnabled(self, enabled):
+        self._graph.activeTheme().setBackgroundEnabled(enabled == Qt.Checked.value)
+
+    @Slot(int)
+    def setGridEnabled(self, enabled):
+        self._graph.activeTheme().setGridEnabled(enabled == Qt.Checked.value)
+
+    @Slot()
+    def toggleItemCount(self):
+        if self._itemCount == NUMBER_OF_ITEMS:
+            self._itemCount = LOWER_NUMBER_OF_ITEMS
+            self._CURVE_DIVIDER = LOWER_CURVE_DIVIDER
+        else:
+            self._itemCount = NUMBER_OF_ITEMS
+            self._CURVE_DIVIDER = CURVE_DIVIDER
+
+        self._graph.seriesList()[0].dataProxy().resetArray([])
+        self.addData()
+
+    @Slot()
+    def toggleRanges(self):
+        if not self._autoAdjust:
+            self._graph.axisX().setAutoAdjustRange(True)
+            self._graph.axisZ().setAutoAdjustRange(True)
+            self._inputHandler.setDragSpeedModifier(1.5)
+            self._autoAdjust = True
+        else:
+            self._graph.axisX().setRange(-10.0, 10.0)
+            self._graph.axisZ().setRange(-10.0, 10.0)
+            self._inputHandler.setDragSpeedModifier(15.0)
+            self._autoAdjust = False
diff --git a/examples/graphs/3d/widgetgallery/scattergraph.py b/examples/graphs/3d/widgetgallery/scattergraph.py
new file mode 100644 (file)
index 0000000..79e8933
--- /dev/null
@@ -0,0 +1,121 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtCore import QObject, QSize, Qt
+from PySide6.QtWidgets import (QCheckBox, QComboBox, QCommandLinkButton,
+                               QLabel, QHBoxLayout, QSizePolicy,
+                               QVBoxLayout, QWidget, )
+from PySide6.QtQuickWidgets import QQuickWidget
+from PySide6.QtGraphs import (QAbstract3DSeries, Q3DScatter)
+
+from scatterdatamodifier import ScatterDataModifier
+
+
+class ScatterGraph(QObject):
+
+    def __init__(self, minimum_graph_size, maximum_graph_size):
+        super().__init__()
+        self._scatterGraph = Q3DScatter()
+        self._scatterWidget = QWidget()
+        hLayout = QHBoxLayout(self._scatterWidget)
+        self._scatterGraph.setMinimumSize(minimum_graph_size)
+        self._scatterGraph.setMaximumSize(maximum_graph_size)
+        self._scatterGraph.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        self._scatterGraph.setFocusPolicy(Qt.StrongFocus)
+        self._scatterGraph.setResizeMode(QQuickWidget.SizeRootObjectToView)
+        hLayout.addWidget(self._scatterGraph, 1)
+
+        vLayout = QVBoxLayout()
+        hLayout.addLayout(vLayout)
+
+        cameraButton = QCommandLinkButton(self._scatterWidget)
+        cameraButton.setText("Change camera preset")
+        cameraButton.setDescription("Switch between a number of preset camera positions")
+        cameraButton.setIconSize(QSize(0, 0))
+
+        itemCountButton = QCommandLinkButton(self._scatterWidget)
+        itemCountButton.setText("Toggle item count")
+        itemCountButton.setDescription("Switch between 900 and 10000 data points")
+        itemCountButton.setIconSize(QSize(0, 0))
+
+        rangeButton = QCommandLinkButton(self._scatterWidget)
+        rangeButton.setText("Toggle axis ranges")
+        rangeButton.setDescription("Switch between automatic axis ranges and preset ranges")
+        rangeButton.setIconSize(QSize(0, 0))
+
+        backgroundCheckBox = QCheckBox(self._scatterWidget)
+        backgroundCheckBox.setText("Show background")
+        backgroundCheckBox.setChecked(True)
+
+        gridCheckBox = QCheckBox(self._scatterWidget)
+        gridCheckBox.setText("Show grid")
+        gridCheckBox.setChecked(True)
+
+        smoothCheckBox = QCheckBox(self._scatterWidget)
+        smoothCheckBox.setText("Smooth dots")
+        smoothCheckBox.setChecked(True)
+
+        itemStyleList = QComboBox(self._scatterWidget)
+        itemStyleList.addItem("Sphere", QAbstract3DSeries.Mesh.Sphere)
+        itemStyleList.addItem("Cube", QAbstract3DSeries.Mesh.Cube)
+        itemStyleList.addItem("Minimal", QAbstract3DSeries.Mesh.Minimal)
+        itemStyleList.addItem("Point", QAbstract3DSeries.Mesh.Point)
+        itemStyleList.setCurrentIndex(0)
+
+        themeList = QComboBox(self._scatterWidget)
+        themeList.addItem("Qt")
+        themeList.addItem("Primary Colors")
+        themeList.addItem("Digia")
+        themeList.addItem("Stone Moss")
+        themeList.addItem("Army Blue")
+        themeList.addItem("Retro")
+        themeList.addItem("Ebony")
+        themeList.addItem("Isabelle")
+        themeList.setCurrentIndex(3)
+
+        shadowQuality = QComboBox(self._scatterWidget)
+        shadowQuality.addItem("None")
+        shadowQuality.addItem("Low")
+        shadowQuality.addItem("Medium")
+        shadowQuality.addItem("High")
+        shadowQuality.addItem("Low Soft")
+        shadowQuality.addItem("Medium Soft")
+        shadowQuality.addItem("High Soft")
+        shadowQuality.setCurrentIndex(6)
+
+        vLayout.addWidget(cameraButton)
+        vLayout.addWidget(itemCountButton)
+        vLayout.addWidget(rangeButton)
+        vLayout.addWidget(backgroundCheckBox)
+        vLayout.addWidget(gridCheckBox)
+        vLayout.addWidget(smoothCheckBox)
+        vLayout.addWidget(QLabel("Change dot style"))
+        vLayout.addWidget(itemStyleList)
+        vLayout.addWidget(QLabel("Change theme"))
+        vLayout.addWidget(themeList)
+        vLayout.addWidget(QLabel("Adjust shadow quality"))
+        vLayout.addWidget(shadowQuality, 1, Qt.AlignTop)
+
+        self._modifier = ScatterDataModifier(self._scatterGraph, self)
+
+        cameraButton.clicked.connect(self._modifier.changePresetCamera)
+        itemCountButton.clicked.connect(self._modifier.toggleItemCount)
+        rangeButton.clicked.connect(self._modifier.toggleRanges)
+
+        backgroundCheckBox.stateChanged.connect(self._modifier.setBackgroundEnabled)
+        gridCheckBox.stateChanged.connect(self._modifier.setGridEnabled)
+        smoothCheckBox.stateChanged.connect(self._modifier.setSmoothDots)
+
+        self._modifier.backgroundEnabledChanged.connect(backgroundCheckBox.setChecked)
+        self._modifier.gridEnabledChanged.connect(gridCheckBox.setChecked)
+        itemStyleList.currentIndexChanged.connect(self._modifier.changeStyle)
+
+        themeList.currentIndexChanged.connect(self._modifier.changeTheme)
+
+        shadowQuality.currentIndexChanged.connect(self._modifier.changeShadowQuality)
+
+        self._modifier.shadowQualityChanged.connect(shadowQuality.setCurrentIndex)
+        self._scatterGraph.shadowQualityChanged.connect(self._modifier.shadowQualityUpdatedByVisual)
+
+    def scatterWidget(self):
+        return self._scatterWidget
diff --git a/examples/graphs/3d/widgetgallery/surfacegraph.py b/examples/graphs/3d/widgetgallery/surfacegraph.py
new file mode 100644 (file)
index 0000000..4052da8
--- /dev/null
@@ -0,0 +1,256 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from surfacegraphmodifier import SurfaceGraphModifier
+
+from PySide6.QtCore import QObject, Qt
+from PySide6.QtGui import QBrush, QIcon, QLinearGradient, QPainter, QPixmap
+from PySide6.QtWidgets import (QGroupBox, QCheckBox, QLabel, QHBoxLayout,
+                               QPushButton, QRadioButton, QSizePolicy, QSlider,
+                               QVBoxLayout, QWidget)
+from PySide6.QtQuickWidgets import QQuickWidget
+from PySide6.QtGraphs import Q3DSurface
+
+
+def gradientBtoYPB_Pixmap():
+    grBtoY = QLinearGradient(0, 0, 1, 100)
+    grBtoY.setColorAt(1.0, Qt.black)
+    grBtoY.setColorAt(0.67, Qt.blue)
+    grBtoY.setColorAt(0.33, Qt.red)
+    grBtoY.setColorAt(0.0, Qt.yellow)
+    pm = QPixmap(24, 100)
+    with QPainter(pm) as pmp:
+        pmp.setBrush(QBrush(grBtoY))
+        pmp.setPen(Qt.NoPen)
+        pmp.drawRect(0, 0, 24, 100)
+    return pm
+
+
+def gradientGtoRPB_Pixmap():
+    grGtoR = QLinearGradient(0, 0, 1, 100)
+    grGtoR.setColorAt(1.0, Qt.darkGreen)
+    grGtoR.setColorAt(0.5, Qt.yellow)
+    grGtoR.setColorAt(0.2, Qt.red)
+    grGtoR.setColorAt(0.0, Qt.darkRed)
+    pm = QPixmap(24, 100)
+    with QPainter(pm) as pmp:
+        pmp.setBrush(QBrush(grGtoR))
+        pmp.setPen(Qt.NoPen)
+        pmp.drawRect(0, 0, 24, 100)
+    return pm
+
+
+def highlightPixmap():
+    HEIGHT = 400
+    WIDTH = 110
+    BORDER = 10
+    gr = QLinearGradient(0, 0, 1, HEIGHT - 2 * BORDER)
+    gr.setColorAt(1.0, Qt.black)
+    gr.setColorAt(0.8, Qt.darkGreen)
+    gr.setColorAt(0.6, Qt.green)
+    gr.setColorAt(0.4, Qt.yellow)
+    gr.setColorAt(0.2, Qt.red)
+    gr.setColorAt(0.0, Qt.darkRed)
+    pmHighlight = QPixmap(WIDTH, HEIGHT)
+    pmHighlight.fill(Qt.transparent)
+    with QPainter(pmHighlight) as pmpHighlight:
+        pmpHighlight.setBrush(QBrush(gr))
+        pmpHighlight.setPen(Qt.NoPen)
+        pmpHighlight.drawRect(BORDER, BORDER, 35, HEIGHT - 2 * BORDER)
+        pmpHighlight.setPen(Qt.black)
+        step = (HEIGHT - 2 * BORDER) / 5
+        for i in range(0, 6):
+            yPos = i * step + BORDER
+            pmpHighlight.drawLine(BORDER, yPos, 55, yPos)
+            HEIGHT = 550 - (i * 110)
+            pmpHighlight.drawText(60, yPos + 2, f"{HEIGHT} m")
+    return pmHighlight
+
+
+class SurfaceGraph(QObject):
+
+    def __init__(self, minimum_graph_size, maximum_graph_size):
+        super().__init__()
+        self._surfaceGraph = Q3DSurface()
+        self._surfaceWidget = QWidget()
+        hLayout = QHBoxLayout(self._surfaceWidget)
+        self._surfaceGraph.setMinimumSize(minimum_graph_size)
+        self._surfaceGraph.setMaximumSize(maximum_graph_size)
+        self._surfaceGraph.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        self._surfaceGraph.setFocusPolicy(Qt.StrongFocus)
+        self._surfaceGraph.setResizeMode(QQuickWidget.SizeRootObjectToView)
+        hLayout.addWidget(self._surfaceGraph, 1)
+        vLayout = QVBoxLayout()
+        hLayout.addLayout(vLayout)
+        vLayout.setAlignment(Qt.AlignTop)
+        # Create control widgets
+        modelGroupBox = QGroupBox("Model")
+        sqrtSinModelRB = QRadioButton(self._surfaceWidget)
+        sqrtSinModelRB.setText("Sqrt and Sin")
+        sqrtSinModelRB.setChecked(False)
+        heightMapModelRB = QRadioButton(self._surfaceWidget)
+        heightMapModelRB.setText("Multiseries\nHeight Map")
+        heightMapModelRB.setChecked(False)
+        texturedModelRB = QRadioButton(self._surfaceWidget)
+        texturedModelRB.setText("Textured\nTopography")
+        texturedModelRB.setChecked(False)
+        modelVBox = QVBoxLayout()
+        modelVBox.addWidget(sqrtSinModelRB)
+        modelVBox.addWidget(heightMapModelRB)
+        modelVBox.addWidget(texturedModelRB)
+        modelGroupBox.setLayout(modelVBox)
+        selectionGroupBox = QGroupBox("Graph Selection Mode")
+        modeNoneRB = QRadioButton(self._surfaceWidget)
+        modeNoneRB.setText("No selection")
+        modeNoneRB.setChecked(False)
+        modeItemRB = QRadioButton(self._surfaceWidget)
+        modeItemRB.setText("Item")
+        modeItemRB.setChecked(False)
+        modeSliceRowRB = QRadioButton(self._surfaceWidget)
+        modeSliceRowRB.setText("Row Slice")
+        modeSliceRowRB.setChecked(False)
+        modeSliceColumnRB = QRadioButton(self._surfaceWidget)
+        modeSliceColumnRB.setText("Column Slice")
+        modeSliceColumnRB.setChecked(False)
+        selectionVBox = QVBoxLayout()
+        selectionVBox.addWidget(modeNoneRB)
+        selectionVBox.addWidget(modeItemRB)
+        selectionVBox.addWidget(modeSliceRowRB)
+        selectionVBox.addWidget(modeSliceColumnRB)
+        selectionGroupBox.setLayout(selectionVBox)
+        axisGroupBox = QGroupBox("Axis ranges")
+        axisMinSliderX = QSlider(Qt.Horizontal)
+        axisMinSliderX.setMinimum(0)
+        axisMinSliderX.setTickInterval(1)
+        axisMinSliderX.setEnabled(True)
+        axisMaxSliderX = QSlider(Qt.Horizontal)
+        axisMaxSliderX.setMinimum(1)
+        axisMaxSliderX.setTickInterval(1)
+        axisMaxSliderX.setEnabled(True)
+        axisMinSliderZ = QSlider(Qt.Horizontal)
+        axisMinSliderZ.setMinimum(0)
+        axisMinSliderZ.setTickInterval(1)
+        axisMinSliderZ.setEnabled(True)
+        axisMaxSliderZ = QSlider(Qt.Horizontal)
+        axisMaxSliderZ.setMinimum(1)
+        axisMaxSliderZ.setTickInterval(1)
+        axisMaxSliderZ.setEnabled(True)
+        axisVBox = QVBoxLayout(axisGroupBox)
+        axisVBox.addWidget(QLabel("Column range"))
+        axisVBox.addWidget(axisMinSliderX)
+        axisVBox.addWidget(axisMaxSliderX)
+        axisVBox.addWidget(QLabel("Row range"))
+        axisVBox.addWidget(axisMinSliderZ)
+        axisVBox.addWidget(axisMaxSliderZ)
+        # Mode-dependent controls
+        # sqrt-sin
+        colorGroupBox = QGroupBox("Custom gradient")
+
+        pixmap = gradientBtoYPB_Pixmap()
+        gradientBtoYPB = QPushButton(self._surfaceWidget)
+        gradientBtoYPB.setIcon(QIcon(pixmap))
+        gradientBtoYPB.setIconSize(pixmap.size())
+
+        pixmap = gradientGtoRPB_Pixmap()
+        gradientGtoRPB = QPushButton(self._surfaceWidget)
+        gradientGtoRPB.setIcon(QIcon(pixmap))
+        gradientGtoRPB.setIconSize(pixmap.size())
+
+        colorHBox = QHBoxLayout(colorGroupBox)
+        colorHBox.addWidget(gradientBtoYPB)
+        colorHBox.addWidget(gradientGtoRPB)
+        # Multiseries heightmap
+        showGroupBox = QGroupBox("Show Object")
+        showGroupBox.setVisible(False)
+        checkboxShowOilRigOne = QCheckBox("Oil Rig 1")
+        checkboxShowOilRigOne.setChecked(True)
+        checkboxShowOilRigTwo = QCheckBox("Oil Rig 2")
+        checkboxShowOilRigTwo.setChecked(True)
+        checkboxShowRefinery = QCheckBox("Refinery")
+        showVBox = QVBoxLayout()
+        showVBox.addWidget(checkboxShowOilRigOne)
+        showVBox.addWidget(checkboxShowOilRigTwo)
+        showVBox.addWidget(checkboxShowRefinery)
+        showGroupBox.setLayout(showVBox)
+        visualsGroupBox = QGroupBox("Visuals")
+        visualsGroupBox.setVisible(False)
+        checkboxVisualsSeeThrough = QCheckBox("See-Through")
+        checkboxHighlightOil = QCheckBox("Highlight Oil")
+        checkboxShowShadows = QCheckBox("Shadows")
+        checkboxShowShadows.setChecked(True)
+        visualVBox = QVBoxLayout(visualsGroupBox)
+        visualVBox.addWidget(checkboxVisualsSeeThrough)
+        visualVBox.addWidget(checkboxHighlightOil)
+        visualVBox.addWidget(checkboxShowShadows)
+        labelSelection = QLabel("Selection:")
+        labelSelection.setVisible(False)
+        labelSelectedItem = QLabel("Nothing")
+        labelSelectedItem.setVisible(False)
+        # Textured topography heightmap
+        enableTexture = QCheckBox("Surface texture")
+        enableTexture.setVisible(False)
+
+        label = QLabel(self._surfaceWidget)
+        label.setPixmap(highlightPixmap())
+        heightMapGroupBox = QGroupBox("Highlight color map")
+        colorMapVBox = QVBoxLayout()
+        colorMapVBox.addWidget(label)
+        heightMapGroupBox.setLayout(colorMapVBox)
+        heightMapGroupBox.setVisible(False)
+        # Populate vertical layout
+        # Common
+        vLayout.addWidget(modelGroupBox)
+        vLayout.addWidget(selectionGroupBox)
+        vLayout.addWidget(axisGroupBox)
+        # Sqrt Sin
+        vLayout.addWidget(colorGroupBox)
+        # Multiseries heightmap
+        vLayout.addWidget(showGroupBox)
+        vLayout.addWidget(visualsGroupBox)
+        vLayout.addWidget(labelSelection)
+        vLayout.addWidget(labelSelectedItem)
+        # Textured topography
+        vLayout.addWidget(heightMapGroupBox)
+        vLayout.addWidget(enableTexture)
+        # Create the controller
+        modifier = SurfaceGraphModifier(self._surfaceGraph, labelSelectedItem, self)
+        # Connect widget controls to controller
+        heightMapModelRB.toggled.connect(modifier.enableHeightMapModel)
+        sqrtSinModelRB.toggled.connect(modifier.enableSqrtSinModel)
+        texturedModelRB.toggled.connect(modifier.enableTopographyModel)
+        modeNoneRB.toggled.connect(modifier.toggleModeNone)
+        modeItemRB.toggled.connect(modifier.toggleModeItem)
+        modeSliceRowRB.toggled.connect(modifier.toggleModeSliceRow)
+        modeSliceColumnRB.toggled.connect(modifier.toggleModeSliceColumn)
+        axisMinSliderX.valueChanged.connect(modifier.adjustXMin)
+        axisMaxSliderX.valueChanged.connect(modifier.adjustXMax)
+        axisMinSliderZ.valueChanged.connect(modifier.adjustZMin)
+        axisMaxSliderZ.valueChanged.connect(modifier.adjustZMax)
+        # Mode dependent connections
+        gradientBtoYPB.pressed.connect(modifier.setBlackToYellowGradient)
+        gradientGtoRPB.pressed.connect(modifier.setGreenToRedGradient)
+        checkboxShowOilRigOne.stateChanged.connect(modifier.toggleItemOne)
+        checkboxShowOilRigTwo.stateChanged.connect(modifier.toggleItemTwo)
+        checkboxShowRefinery.stateChanged.connect(modifier.toggleItemThree)
+        checkboxVisualsSeeThrough.stateChanged.connect(modifier.toggleSeeThrough)
+        checkboxHighlightOil.stateChanged.connect(modifier.toggleOilHighlight)
+        checkboxShowShadows.stateChanged.connect(modifier.toggleShadows)
+        enableTexture.stateChanged.connect(modifier.toggleSurfaceTexture)
+        # Connections to disable features depending on mode
+        sqrtSinModelRB.toggled.connect(colorGroupBox.setVisible)
+        heightMapModelRB.toggled.connect(showGroupBox.setVisible)
+        heightMapModelRB.toggled.connect(visualsGroupBox.setVisible)
+        heightMapModelRB.toggled.connect(labelSelection.setVisible)
+        heightMapModelRB.toggled.connect(labelSelectedItem.setVisible)
+        texturedModelRB.toggled.connect(enableTexture.setVisible)
+        texturedModelRB.toggled.connect(heightMapGroupBox.setVisible)
+        modifier.setAxisMinSliderX(axisMinSliderX)
+        modifier.setAxisMaxSliderX(axisMaxSliderX)
+        modifier.setAxisMinSliderZ(axisMinSliderZ)
+        modifier.setAxisMaxSliderZ(axisMaxSliderZ)
+        sqrtSinModelRB.setChecked(True)
+        modeItemRB.setChecked(True)
+        enableTexture.setChecked(True)
+
+    def surfaceWidget(self):
+        return self._surfaceWidget
diff --git a/examples/graphs/3d/widgetgallery/surfacegraphmodifier.py b/examples/graphs/3d/widgetgallery/surfacegraphmodifier.py
new file mode 100644 (file)
index 0000000..b2706c6
--- /dev/null
@@ -0,0 +1,641 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import os
+from math import sqrt, sin
+from pathlib import Path
+
+from PySide6.QtCore import QObject, QPropertyAnimation, Qt, Slot
+from PySide6.QtGui import (QColor, QFont, QImage, QLinearGradient,
+                           QQuaternion, QVector3D)
+from PySide6.QtGraphs import (QAbstract3DGraph, QCustom3DItem,
+                              QCustom3DLabel, QHeightMapSurfaceDataProxy,
+                              QValue3DAxis, QSurfaceDataItem,
+                              QSurfaceDataProxy, QSurface3DSeries,
+                              Q3DInputHandler, Q3DTheme)
+
+
+from highlightseries import HighlightSeries
+from topographicseries import TopographicSeries
+from custominputhandler import CustomInputHandler
+
+
+SAMPLE_COUNT_X = 150
+SAMPLE_COUNT_Z = 150
+HEIGHTMAP_GRID_STEP_X = 6
+HEIGHTMAP_GRID_STEP_Z = 6
+SAMPLE_MIN = -8.0
+SAMPLE_MAX = 8.0
+
+AREA_WIDTH = 8000.0
+AREA_HEIGHT = 8000.0
+ASPECT_RATIO = 0.1389
+MIN_RANGE = AREA_WIDTH * 0.49
+
+
+class SurfaceGraphModifier(QObject):
+
+    def __init__(self, surface, label, parent):
+        super().__init__(parent)
+        self._data_path = Path(__file__).resolve().parent / "data"
+        self._graph = surface
+        self._textField = label
+        self._sqrtSinProxy = None
+        self._sqrtSinSeries = None
+        self._heightMapProxyOne = None
+        self._heightMapProxyTwo = None
+        self._heightMapProxyThree = None
+        self._heightMapSeriesOne = None
+        self._heightMapSeriesTwo = None
+        self._heightMapSeriesThree = None
+
+        self._axisMinSliderX = None
+        self._axisMaxSliderX = None
+        self._axisMinSliderZ = None
+        self._axisMaxSliderZ = None
+        self._rangeMinX = 0.0
+        self._rangeMinZ = 0.0
+        self._stepX = 0.0
+        self._stepZ = 0.0
+        self._heightMapWidth = 0
+        self._heightMapHeight = 0
+
+        self._selectionAnimation = None
+        self._titleLabel = None
+        self._previouslyAnimatedItem = None
+        self._previousScaling = {}
+
+        self._topography = None
+        self._highlight = None
+        self._highlightWidth = 0
+        self._highlightHeight = 0
+
+        self._customInputHandler = None
+        self._defaultInputHandler = Q3DInputHandler()
+
+        self._graph.setCameraZoomLevel(85.0)
+        self._graph.setCameraPreset(QAbstract3DGraph.CameraPreset.IsometricRight)
+        self._graph.activeTheme().setType(Q3DTheme.Theme.Retro)
+
+        self._x_axis = QValue3DAxis()
+        self._y_axis = QValue3DAxis()
+        self._z_axis = QValue3DAxis()
+        self._graph.setAxisX(self._x_axis)
+        self._graph.setAxisY(self._y_axis)
+        self._graph.setAxisZ(self._z_axis)
+
+        #
+        # Sqrt Sin
+        #
+        self._sqrtSinProxy = QSurfaceDataProxy()
+        self._sqrtSinSeries = QSurface3DSeries(self._sqrtSinProxy)
+        self.fillSqrtSinProxy()
+
+        #
+        # Multisurface heightmap
+        #
+        # Create the first surface layer
+        heightMapImageOne = QImage(self._data_path / "layer_1.png")
+        self._heightMapProxyOne = QHeightMapSurfaceDataProxy(heightMapImageOne)
+        self._heightMapSeriesOne = QSurface3DSeries(self._heightMapProxyOne)
+        self._heightMapSeriesOne.setItemLabelFormat("(@xLabel, @zLabel): @yLabel")
+        self._heightMapProxyOne.setValueRanges(34.0, 40.0, 18.0, 24.0)
+
+        # Create the other 2 surface layers
+        heightMapImageTwo = QImage(self._data_path / "layer_2.png")
+        self._heightMapProxyTwo = QHeightMapSurfaceDataProxy(heightMapImageTwo)
+        self._heightMapSeriesTwo = QSurface3DSeries(self._heightMapProxyTwo)
+        self._heightMapSeriesTwo.setItemLabelFormat("(@xLabel, @zLabel): @yLabel")
+        self._heightMapProxyTwo.setValueRanges(34.0, 40.0, 18.0, 24.0)
+
+        heightMapImageThree = QImage(self._data_path / "layer_3.png")
+        self._heightMapProxyThree = QHeightMapSurfaceDataProxy(heightMapImageThree)
+        self._heightMapSeriesThree = QSurface3DSeries(self._heightMapProxyThree)
+        self._heightMapSeriesThree.setItemLabelFormat("(@xLabel, @zLabel): @yLabel")
+        self._heightMapProxyThree.setValueRanges(34.0, 40.0, 18.0, 24.0)
+
+        # The images are the same size, so it's enough to get the dimensions
+        # from one
+        self._heightMapWidth = heightMapImageOne.width()
+        self._heightMapHeight = heightMapImageOne.height()
+
+        # Set the gradients for multi-surface layers
+        grOne = QLinearGradient()
+        grOne.setColorAt(0.0, Qt.black)
+        grOne.setColorAt(0.38, Qt.darkYellow)
+        grOne.setColorAt(0.39, Qt.darkGreen)
+        grOne.setColorAt(0.5, Qt.darkGray)
+        grOne.setColorAt(1.0, Qt.gray)
+        self._heightMapSeriesOne.setBaseGradient(grOne)
+        self._heightMapSeriesOne.setColorStyle(Q3DTheme.ColorStyle.RangeGradient)
+
+        grTwo = QLinearGradient()
+        grTwo.setColorAt(0.39, Qt.blue)
+        grTwo.setColorAt(0.4, Qt.white)
+        self._heightMapSeriesTwo.setBaseGradient(grTwo)
+        self._heightMapSeriesTwo.setColorStyle(Q3DTheme.ColorStyle.RangeGradient)
+
+        grThree = QLinearGradient()
+        grThree.setColorAt(0.0, Qt.white)
+        grThree.setColorAt(0.05, Qt.black)
+        self._heightMapSeriesThree.setBaseGradient(grThree)
+        self._heightMapSeriesThree.setColorStyle(Q3DTheme.ColorStyle.RangeGradient)
+
+        # Custom items and label
+        self._graph.selectedElementChanged.connect(self.handleElementSelected)
+
+        self._selectionAnimation = QPropertyAnimation(self)
+        self._selectionAnimation.setPropertyName(b"scaling")
+        self._selectionAnimation.setDuration(500)
+        self._selectionAnimation.setLoopCount(-1)
+
+        titleFont = QFont("Century Gothic", 30)
+        titleFont.setBold(True)
+        self._titleLabel = QCustom3DLabel("Oil Rigs on Imaginary Sea", titleFont,
+                                          QVector3D(0.0, 1.2, 0.0),
+                                          QVector3D(1.0, 1.0, 0.0),
+                                          QQuaternion())
+        self._titleLabel.setPositionAbsolute(True)
+        self._titleLabel.setFacingCamera(True)
+        self._titleLabel.setBackgroundColor(QColor(0x66cdaa))
+        self._graph.addCustomItem(self._titleLabel)
+        self._titleLabel.setVisible(False)
+
+        # Make two of the custom object visible
+        self.toggleItemOne(True)
+        self.toggleItemTwo(True)
+
+        #
+        # Topographic map
+        #
+        self._topography = TopographicSeries()
+        file_name = os.fspath(self._data_path / "topography.png")
+        self._topography.setTopographyFile(file_name, AREA_WIDTH, AREA_HEIGHT)
+        self._topography.setItemLabelFormat("@yLabel m")
+
+        self._highlight = HighlightSeries()
+        self._highlight.setTopographicSeries(self._topography)
+        self._highlight.setMinHeight(MIN_RANGE * ASPECT_RATIO)
+        self._highlight.handleGradientChange(AREA_WIDTH * ASPECT_RATIO)
+        self._graph.axisY().maxChanged.connect(self._highlight.handleGradientChange)
+
+        self._customInputHandler = CustomInputHandler(self._graph)
+        self._customInputHandler.setHighlightSeries(self._highlight)
+        self._customInputHandler.setAxes(self._x_axis, self._y_axis, self._z_axis)
+        self._customInputHandler.setLimits(0.0, AREA_WIDTH, MIN_RANGE)
+        self._customInputHandler.setAspectRatio(ASPECT_RATIO)
+
+    def fillSqrtSinProxy(self):
+        stepX = (SAMPLE_MAX - SAMPLE_MIN) / float(SAMPLE_COUNT_X - 1)
+        stepZ = (SAMPLE_MAX - SAMPLE_MIN) / float(SAMPLE_COUNT_Z - 1)
+
+        dataArray = []
+        for i in range(0, SAMPLE_COUNT_Z):
+            newRow = []
+            # Keep values within range bounds, since just adding step can
+            # cause minor drift due to the rounding errors.
+            z = min(SAMPLE_MAX, (i * stepZ + SAMPLE_MIN))
+            for j in range(0, SAMPLE_COUNT_X):
+                x = min(SAMPLE_MAX, (j * stepX + SAMPLE_MIN))
+                R = sqrt(z * z + x * x) + 0.01
+                y = (sin(R) / R + 0.24) * 1.61
+                item = QSurfaceDataItem(QVector3D(x, y, z))
+                newRow.append(item)
+            dataArray.append(newRow)
+        self._sqrtSinProxy.resetArray(dataArray)
+
+    @Slot(bool)
+    def enableSqrtSinModel(self, enable):
+        if enable:
+            self._sqrtSinSeries.setDrawMode(QSurface3DSeries.DrawSurfaceAndWireframe)
+            self._sqrtSinSeries.setFlatShadingEnabled(True)
+
+            self._graph.axisX().setLabelFormat("%.2f")
+            self._graph.axisZ().setLabelFormat("%.2f")
+            self._graph.axisX().setRange(SAMPLE_MIN, SAMPLE_MAX)
+            self._graph.axisY().setRange(0.0, 2.0)
+            self._graph.axisZ().setRange(SAMPLE_MIN, SAMPLE_MAX)
+            self._graph.axisX().setLabelAutoRotation(30.0)
+            self._graph.axisY().setLabelAutoRotation(90.0)
+            self._graph.axisZ().setLabelAutoRotation(30.0)
+
+            self._graph.removeSeries(self._heightMapSeriesOne)
+            self._graph.removeSeries(self._heightMapSeriesTwo)
+            self._graph.removeSeries(self._heightMapSeriesThree)
+            self._graph.removeSeries(self._topography)
+            self._graph.removeSeries(self._highlight)
+
+            self._graph.addSeries(self._sqrtSinSeries)
+
+            self._titleLabel.setVisible(False)
+            self._graph.axisX().setTitleVisible(False)
+            self._graph.axisY().setTitleVisible(False)
+            self._graph.axisZ().setTitleVisible(False)
+
+            self._graph.axisX().setTitle("")
+            self._graph.axisY().setTitle("")
+            self._graph.axisZ().setTitle("")
+
+            self._graph.setActiveInputHandler(self._defaultInputHandler)
+
+            # Reset range sliders for Sqrt & Sin
+            self._rangeMinX = SAMPLE_MIN
+            self._rangeMinZ = SAMPLE_MIN
+            self._stepX = (SAMPLE_MAX - SAMPLE_MIN) / float(SAMPLE_COUNT_X - 1)
+            self._stepZ = (SAMPLE_MAX - SAMPLE_MIN) / float(SAMPLE_COUNT_Z - 1)
+            self._axisMinSliderX.setMinimum(0)
+            self._axisMinSliderX.setMaximum(SAMPLE_COUNT_X - 2)
+            self._axisMinSliderX.setValue(0)
+            self._axisMaxSliderX.setMinimum(1)
+            self._axisMaxSliderX.setMaximum(SAMPLE_COUNT_X - 1)
+            self._axisMaxSliderX.setValue(SAMPLE_COUNT_X - 1)
+            self._axisMinSliderZ.setMinimum(0)
+            self._axisMinSliderZ.setMaximum(SAMPLE_COUNT_Z - 2)
+            self._axisMinSliderZ.setValue(0)
+            self._axisMaxSliderZ.setMinimum(1)
+            self._axisMaxSliderZ.setMaximum(SAMPLE_COUNT_Z - 1)
+            self._axisMaxSliderZ.setValue(SAMPLE_COUNT_Z - 1)
+
+    @Slot(bool)
+    def enableHeightMapModel(self, enable):
+        if enable:
+            self._heightMapSeriesOne.setDrawMode(QSurface3DSeries.DrawSurface)
+            self._heightMapSeriesOne.setFlatShadingEnabled(False)
+            self._heightMapSeriesTwo.setDrawMode(QSurface3DSeries.DrawSurface)
+            self._heightMapSeriesTwo.setFlatShadingEnabled(False)
+            self._heightMapSeriesThree.setDrawMode(QSurface3DSeries.DrawSurface)
+            self._heightMapSeriesThree.setFlatShadingEnabled(False)
+
+            self._graph.axisX().setLabelFormat("%.1f N")
+            self._graph.axisZ().setLabelFormat("%.1f E")
+            self._graph.axisX().setRange(34.0, 40.0)
+            self._graph.axisY().setAutoAdjustRange(True)
+            self._graph.axisZ().setRange(18.0, 24.0)
+
+            self._graph.axisX().setTitle("Latitude")
+            self._graph.axisY().setTitle("Height")
+            self._graph.axisZ().setTitle("Longitude")
+
+            self._graph.removeSeries(self._sqrtSinSeries)
+            self._graph.removeSeries(self._topography)
+            self._graph.removeSeries(self._highlight)
+            self._graph.addSeries(self._heightMapSeriesOne)
+            self._graph.addSeries(self._heightMapSeriesTwo)
+            self._graph.addSeries(self._heightMapSeriesThree)
+
+            self._graph.setActiveInputHandler(self._defaultInputHandler)
+
+            self._titleLabel.setVisible(True)
+            self._graph.axisX().setTitleVisible(True)
+            self._graph.axisY().setTitleVisible(True)
+            self._graph.axisZ().setTitleVisible(True)
+
+            # Reset range sliders for height map
+            mapGridCountX = self._heightMapWidth / HEIGHTMAP_GRID_STEP_X
+            mapGridCountZ = self._heightMapHeight / HEIGHTMAP_GRID_STEP_Z
+            self._rangeMinX = 34.0
+            self._rangeMinZ = 18.0
+            self._stepX = 6.0 / float(mapGridCountX - 1)
+            self._stepZ = 6.0 / float(mapGridCountZ - 1)
+            self._axisMinSliderX.setMinimum(0)
+            self._axisMinSliderX.setMaximum(mapGridCountX - 2)
+            self._axisMinSliderX.setValue(0)
+            self._axisMaxSliderX.setMinimum(1)
+            self._axisMaxSliderX.setMaximum(mapGridCountX - 1)
+            self._axisMaxSliderX.setValue(mapGridCountX - 1)
+            self._axisMinSliderZ.setMinimum(0)
+            self._axisMinSliderZ.setMaximum(mapGridCountZ - 2)
+            self._axisMinSliderZ.setValue(0)
+            self._axisMaxSliderZ.setMinimum(1)
+            self._axisMaxSliderZ.setMaximum(mapGridCountZ - 1)
+            self._axisMaxSliderZ.setValue(mapGridCountZ - 1)
+
+    @Slot(bool)
+    def enableTopographyModel(self, enable):
+        if enable:
+            self._graph.axisX().setLabelFormat("%i")
+            self._graph.axisZ().setLabelFormat("%i")
+            self._graph.axisX().setRange(0.0, AREA_WIDTH)
+            self._graph.axisY().setRange(100.0, AREA_WIDTH * ASPECT_RATIO)
+            self._graph.axisZ().setRange(0.0, AREA_HEIGHT)
+            self._graph.axisX().setLabelAutoRotation(30.0)
+            self._graph.axisY().setLabelAutoRotation(90.0)
+            self._graph.axisZ().setLabelAutoRotation(30.0)
+
+            self._graph.removeSeries(self._heightMapSeriesOne)
+            self._graph.removeSeries(self._heightMapSeriesTwo)
+            self._graph.removeSeries(self._heightMapSeriesThree)
+            self._graph.addSeries(self._topography)
+            self._graph.addSeries(self._highlight)
+
+            self._titleLabel.setVisible(False)
+            self._graph.axisX().setTitleVisible(False)
+            self._graph.axisY().setTitleVisible(False)
+            self._graph.axisZ().setTitleVisible(False)
+
+            self._graph.axisX().setTitle("")
+            self._graph.axisY().setTitle("")
+            self._graph.axisZ().setTitle("")
+
+            self._graph.setActiveInputHandler(self._customInputHandler)
+
+            # Reset range sliders for topography map
+            self._rangeMinX = 0.0
+            self._rangeMinZ = 0.0
+            self._stepX = 1.0
+            self._stepZ = 1.0
+            self._axisMinSliderX.setMinimum(0)
+            self._axisMinSliderX.setMaximum(AREA_WIDTH - 200)
+            self._axisMinSliderX.setValue(0)
+            self._axisMaxSliderX.setMinimum(200)
+            self._axisMaxSliderX.setMaximum(AREA_WIDTH)
+            self._axisMaxSliderX.setValue(AREA_WIDTH)
+            self._axisMinSliderZ.setMinimum(0)
+            self._axisMinSliderZ.setMaximum(AREA_HEIGHT - 200)
+            self._axisMinSliderZ.setValue(0)
+            self._axisMaxSliderZ.setMinimum(200)
+            self._axisMaxSliderZ.setMaximum(AREA_HEIGHT)
+            self._axisMaxSliderZ.setValue(AREA_HEIGHT)
+
+    def adjustXMin(self, min):
+        minX = self._stepX * float(min) + self._rangeMinX
+
+        max = self._axisMaxSliderX.value()
+        if min >= max:
+            max = min + 1
+            self._axisMaxSliderX.setValue(max)
+
+        maxX = self._stepX * max + self._rangeMinX
+
+        self.setAxisXRange(minX, maxX)
+
+    def adjustXMax(self, max):
+        maxX = self._stepX * float(max) + self._rangeMinX
+
+        min = self._axisMinSliderX.value()
+        if max <= min:
+            min = max - 1
+            self._axisMinSliderX.setValue(min)
+
+        minX = self._stepX * min + self._rangeMinX
+
+        self.setAxisXRange(minX, maxX)
+
+    def adjustZMin(self, min):
+        minZ = self._stepZ * float(min) + self._rangeMinZ
+
+        max = self._axisMaxSliderZ.value()
+        if min >= max:
+            max = min + 1
+            self._axisMaxSliderZ.setValue(max)
+
+        maxZ = self._stepZ * max + self._rangeMinZ
+
+        self.setAxisZRange(minZ, maxZ)
+
+    def adjustZMax(self, max):
+        maxX = self._stepZ * float(max) + self._rangeMinZ
+
+        min = self._axisMinSliderZ.value()
+        if max <= min:
+            min = max - 1
+            self._axisMinSliderZ.setValue(min)
+
+        minX = self._stepZ * min + self._rangeMinZ
+
+        self.setAxisZRange(minX, maxX)
+
+    def setAxisXRange(self, min, max):
+        self._graph.axisX().setRange(min, max)
+
+    def setAxisZRange(self, min, max):
+        self._graph.axisZ().setRange(min, max)
+
+    def setBlackToYellowGradient(self):
+        gr = QLinearGradient()
+        gr.setColorAt(0.0, Qt.black)
+        gr.setColorAt(0.33, Qt.blue)
+        gr.setColorAt(0.67, Qt.red)
+        gr.setColorAt(1.0, Qt.yellow)
+
+        self._sqrtSinSeries.setBaseGradient(gr)
+        self._sqrtSinSeries.setColorStyle(Q3DTheme.ColorStyle.RangeGradient)
+
+    def setGreenToRedGradient(self):
+        gr = QLinearGradient()
+        gr.setColorAt(0.0, Qt.darkGreen)
+        gr.setColorAt(0.5, Qt.yellow)
+        gr.setColorAt(0.8, Qt.red)
+        gr.setColorAt(1.0, Qt.darkRed)
+
+        self._sqrtSinSeries.setBaseGradient(gr)
+        self._sqrtSinSeries.setColorStyle(Q3DTheme.ColorStyle.RangeGradient)
+
+    @Slot(bool)
+    def toggleItemOne(self, show):
+        positionOne = QVector3D(39.0, 77.0, 19.2)
+        positionOnePipe = QVector3D(39.0, 45.0, 19.2)
+        positionOneLabel = QVector3D(39.0, 107.0, 19.2)
+        if show:
+            color = QImage(2, 2, QImage.Format_RGB32)
+            color.fill(Qt.red)
+            file_name = os.fspath(self._data_path / "oilrig.mesh")
+            item = QCustom3DItem(file_name, positionOne,
+                                 QVector3D(0.025, 0.025, 0.025),
+                                 QQuaternion.fromAxisAndAngle(0.0, 1.0, 0.0, 45.0),
+                                 color)
+            self._graph.addCustomItem(item)
+            file_name = os.fspath(self._data_path / "pipe.mesh")
+            item = QCustom3DItem(file_name, positionOnePipe,
+                                 QVector3D(0.005, 0.5, 0.005), QQuaternion(),
+                                 color)
+            item.setShadowCasting(False)
+            self._graph.addCustomItem(item)
+
+            label = QCustom3DLabel()
+            label.setText("Oil Rig One")
+            label.setPosition(positionOneLabel)
+            label.setScaling(QVector3D(1.0, 1.0, 1.0))
+            self._graph.addCustomItem(label)
+        else:
+            self.resetSelection()
+            self._graph.removeCustomItemAt(positionOne)
+            self._graph.removeCustomItemAt(positionOnePipe)
+            self._graph.removeCustomItemAt(positionOneLabel)
+
+    @Slot(bool)
+    def toggleItemTwo(self, show):
+        positionTwo = QVector3D(34.5, 77.0, 23.4)
+        positionTwoPipe = QVector3D(34.5, 45.0, 23.4)
+        positionTwoLabel = QVector3D(34.5, 107.0, 23.4)
+        if show:
+            color = QImage(2, 2, QImage.Format_RGB32)
+            color.fill(Qt.red)
+            item = QCustom3DItem()
+            file_name = os.fspath(self._data_path / "oilrig.mesh")
+            item.setMeshFile(file_name)
+            item.setPosition(positionTwo)
+            item.setScaling(QVector3D(0.025, 0.025, 0.025))
+            item.setRotation(QQuaternion.fromAxisAndAngle(0.0, 1.0, 0.0, 25.0))
+            item.setTextureImage(color)
+            self._graph.addCustomItem(item)
+            file_name = os.fspath(self._data_path / "pipe.mesh")
+            item = QCustom3DItem(file_name, positionTwoPipe,
+                                 QVector3D(0.005, 0.5, 0.005), QQuaternion(),
+                                 color)
+            item.setShadowCasting(False)
+            self._graph.addCustomItem(item)
+
+            label = QCustom3DLabel()
+            label.setText("Oil Rig Two")
+            label.setPosition(positionTwoLabel)
+            label.setScaling(QVector3D(1.0, 1.0, 1.0))
+            self._graph.addCustomItem(label)
+        else:
+            self.resetSelection()
+            self._graph.removeCustomItemAt(positionTwo)
+            self._graph.removeCustomItemAt(positionTwoPipe)
+            self._graph.removeCustomItemAt(positionTwoLabel)
+
+    @Slot(bool)
+    def toggleItemThree(self, show):
+        positionThree = QVector3D(34.5, 86.0, 19.1)
+        positionThreeLabel = QVector3D(34.5, 116.0, 19.1)
+        if show:
+            color = QImage(2, 2, QImage.Format_RGB32)
+            color.fill(Qt.darkMagenta)
+            item = QCustom3DItem()
+            file_name = os.fspath(self._data_path / "refinery.mesh")
+            item.setMeshFile(file_name)
+            item.setPosition(positionThree)
+            item.setScaling(QVector3D(0.04, 0.04, 0.04))
+            item.setRotation(QQuaternion.fromAxisAndAngle(0.0, 1.0, 0.0, 75.0))
+            item.setTextureImage(color)
+            self._graph.addCustomItem(item)
+
+            label = QCustom3DLabel()
+            label.setText("Refinery")
+            label.setPosition(positionThreeLabel)
+            label.setScaling(QVector3D(1.0, 1.0, 1.0))
+            self._graph.addCustomItem(label)
+        else:
+            self.resetSelection()
+            self._graph.removeCustomItemAt(positionThree)
+            self._graph.removeCustomItemAt(positionThreeLabel)
+
+    @Slot(bool)
+    def toggleSeeThrough(self, seethrough):
+        s0 = self._graph.seriesList()[0]
+        s1 = self._graph.seriesList()[1]
+        if seethrough:
+            s0.setDrawMode(QSurface3DSeries.DrawWireframe)
+            s1.setDrawMode(QSurface3DSeries.DrawWireframe)
+        else:
+            s0.setDrawMode(QSurface3DSeries.DrawSurface)
+            s1.setDrawMode(QSurface3DSeries.DrawSurface)
+
+    @Slot(bool)
+    def toggleOilHighlight(self, highlight):
+        s2 = self._graph.seriesList()[2]
+        if highlight:
+            grThree = QLinearGradient()
+            grThree.setColorAt(0.0, Qt.black)
+            grThree.setColorAt(0.05, Qt.red)
+            s2.setBaseGradient(grThree)
+        else:
+            grThree = QLinearGradient()
+            grThree.setColorAt(0.0, Qt.white)
+            grThree.setColorAt(0.05, Qt.black)
+            s2.setBaseGradient(grThree)
+
+    @Slot(bool)
+    def toggleShadows(self, shadows):
+        sq = (QAbstract3DGraph.ShadowQualityMedium
+              if shadows else QAbstract3DGraph.ShadowQualityNone)
+        self._graph.setShadowQuality(sq)
+
+    @Slot(bool)
+    def toggleSurfaceTexture(self, enable):
+        if enable:
+            file_name = os.fspath(self._data_path / "maptexture.jpg")
+            self._topography.setTextureFile(file_name)
+        else:
+            self._topography.setTextureFile("")
+
+    def handleElementSelected(self, type):
+        self.resetSelection()
+        if type == QAbstract3DGraph.ElementCustomItem:
+            item = self._graph.selectedCustomItem()
+            text = ""
+            if isinstance(item, QCustom3DItem):
+                text += "Custom label: "
+            else:
+                file = item.meshFile().split("/")[-1]
+                text += f"{file}: "
+
+            text += str(self._graph.selectedCustomItemIndex())
+            self._textField.setText(text)
+            self._previouslyAnimatedItem = item
+            self._previousScaling = item.scaling()
+            self._selectionAnimation.setTargetObject(item)
+            self._selectionAnimation.setStartValue(item.scaling())
+            self._selectionAnimation.setEndValue(item.scaling() * 1.5)
+            self._selectionAnimation.start()
+        elif type == QAbstract3DGraph.ElementSeries:
+            text = "Surface ("
+            series = self._graph.selectedSeries()
+            if series:
+                point = series.selectedPoint()
+                text += f"{point.x()}, {point.y()}"
+            text += ")"
+            self._textField.setText(text)
+        elif (type.value > QAbstract3DGraph.ElementSeries.value
+              and type < QAbstract3DGraph.ElementCustomItem.value):
+            index = self._graph.selectedLabelIndex()
+            text = ""
+            if type == QAbstract3DGraph.ElementAxisXLabel:
+                text += "Axis X label: "
+            elif type == QAbstract3DGraph.ElementAxisYLabel:
+                text += "Axis Y label: "
+            else:
+                text += "Axis Z label: "
+            text += str(index)
+            self._textField.setText(text)
+        else:
+            self._textField.setText("Nothing")
+
+    def resetSelection(self):
+        self._selectionAnimation.stop()
+        if self._previouslyAnimatedItem:
+            self._previouslyAnimatedItem.setScaling(self._previousScaling)
+        self._previouslyAnimatedItem = None
+
+    def toggleModeNone(self):
+        self._graph.setSelectionMode(QAbstract3DGraph.SelectionNone)
+
+    def toggleModeItem(self):
+        self._graph.setSelectionMode(QAbstract3DGraph.SelectionItem)
+
+    def toggleModeSliceRow(self):
+        sm = (QAbstract3DGraph.SelectionItemAndRow
+              | QAbstract3DGraph.SelectionSlice
+              | QAbstract3DGraph.SelectionMultiSeries)
+        self._graph.setSelectionMode(sm)
+
+    def toggleModeSliceColumn(self):
+        sm = (QAbstract3DGraph.SelectionItemAndColumn
+              | QAbstract3DGraph.SelectionSlice
+              | QAbstract3DGraph.SelectionMultiSeries)
+        self._graph.setSelectionMode(sm)
+
+    def setAxisMinSliderX(self, slider):
+        self._axisMinSliderX = slider
+
+    def setAxisMaxSliderX(self, slider):
+        self._axisMaxSliderX = slider
+
+    def setAxisMinSliderZ(self, slider):
+        self._axisMinSliderZ = slider
+
+    def setAxisMaxSliderZ(self, slider):
+        self._axisMaxSliderZ = slider
diff --git a/examples/graphs/3d/widgetgallery/topographicseries.py b/examples/graphs/3d/widgetgallery/topographicseries.py
new file mode 100644 (file)
index 0000000..4f286a2
--- /dev/null
@@ -0,0 +1,57 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtCore import Qt
+from PySide6.QtGui import QImage, QVector3D
+from PySide6.QtGraphs import (QSurface3DSeries, QSurfaceDataItem)
+
+
+# Value used to encode height data as RGB value on PNG file
+PACKING_FACTOR = 11983.0
+
+
+class TopographicSeries(QSurface3DSeries):
+
+    def __init__(self):
+        super().__init__()
+        self._sampleCountX = 0.0
+        self._sampleCountZ = 0.0
+        self.setDrawMode(QSurface3DSeries.DrawSurface)
+        self.setFlatShadingEnabled(True)
+        self.setBaseColor(Qt.white)
+
+    def sampleCountX(self):
+        return self._sampleCountX
+
+    def sampleCountZ(self):
+        return self._sampleCountZ
+
+    def setTopographyFile(self, file, width, height):
+        heightMapImage = QImage(file)
+        bits = heightMapImage.bits()
+        imageHeight = heightMapImage.height()
+        imageWidth = heightMapImage.width()
+        widthBits = imageWidth * 4
+        stepX = width / float(imageWidth)
+        stepZ = height / float(imageHeight)
+
+        dataArray = []
+        for i in range(0, imageHeight):
+            p = i * widthBits
+            z = height - float(i) * stepZ
+            newRow = []
+            for j in range(0, imageWidth):
+                aa = bits[p + 0]
+                rr = bits[p + 1]
+                gg = bits[p + 2]
+                color = (gg << 16) + (rr << 8) + aa
+                y = float(color) / PACKING_FACTOR
+                item = QSurfaceDataItem(QVector3D(float(j) * stepX, y, z))
+                newRow.append(item)
+                p += 4
+            dataArray.append(newRow)
+
+        self.dataProxy().resetArray(dataArray)
+
+        self._sampleCountX = float(imageWidth)
+        self._sampleCountZ = float(imageHeight)
diff --git a/examples/graphs/3d/widgetgallery/variantbardatamapping.py b/examples/graphs/3d/widgetgallery/variantbardatamapping.py
new file mode 100644 (file)
index 0000000..50bdefa
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtCore import QObject, Signal
+
+
+class VariantBarDataMapping(QObject):
+
+    rowIndexChanged = Signal()
+    columnIndexChanged = Signal()
+    valueIndexChanged = Signal()
+    rowCategoriesChanged = Signal()
+    columnCategoriesChanged = Signal()
+    mappingChanged = Signal()
+
+    def __init__(self, rowIndex, columnIndex, valueIndex,
+                 rowCategories=[], columnCategories=[]):
+        super().__init__(None)
+        self._rowIndex = rowIndex
+        self._columnIndex = columnIndex
+        self._valueIndex = valueIndex
+        self._rowCategories = rowCategories
+        self._columnCategories = columnCategories
+
+    def setRowIndex(self, index):
+        self._rowIndex = index
+        self.mappingChanged.emit()
+
+    def rowIndex(self):
+        return self._rowIndex
+
+    def setColumnIndex(self, index):
+        self._columnIndex = index
+        self.mappingChanged.emit()
+
+    def columnIndex(self):
+        return self._columnIndex
+
+    def setValueIndex(self, index):
+        self._valueIndex = index
+        self.mappingChanged.emit()
+
+    def valueIndex(self):
+        return self._valueIndex
+
+    def setRowCategories(self, categories):
+        self._rowCategories = categories
+        self.mappingChanged.emit()
+
+    def rowCategories(self):
+        return self._rowCategories
+
+    def setColumnCategories(self, categories):
+        self._columnCategories = categories
+        self.mappingChanged.emit()
+
+    def columnCategories(self):
+        return self._columnCategories
+
+    def remap(self, rowIndex, columnIndex, valueIndex,
+              rowCategories=[], columnCategories=[]):
+        self._rowIndex = rowIndex
+        self._columnIndex = columnIndex
+        self._valueIndex = valueIndex
+        self._rowCategories = rowCategories
+        self._columnCategories = columnCategories
+        self.mappingChanged.emit()
diff --git a/examples/graphs/3d/widgetgallery/variantbardataproxy.py b/examples/graphs/3d/widgetgallery/variantbardataproxy.py
new file mode 100644 (file)
index 0000000..5ab2a2c
--- /dev/null
@@ -0,0 +1,100 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtCore import Slot
+from PySide6.QtGraphs import QBarDataProxy, QBarDataItem
+
+
+class VariantBarDataProxy(QBarDataProxy):
+
+    def __init__(self):
+        super().__init__()
+        self._dataSet = None
+        self._mapping = None
+
+    def setDataSet(self, newSet):
+        if self._dataSet:
+            self._dataSet.itemsAdded.disconnect(self.handleItemsAdded)
+            self._dataSet.dataCleared.disconnect(self.handleDataCleared)
+
+        self._dataSet = newSet
+
+        if self._dataSet:
+            self._dataSet.itemsAdded.connect(self.handleItemsAdded)
+            self._dataSet.dataCleared.connect(self.handleDataCleared)
+        self.resolveDataSet()
+
+    def dataSet(self):
+        return self._dataSet.data()
+
+    # Map key (row, column, value) to value index in data item (VariantItem).
+    # Doesn't gain ownership of mapping, but does connect to it to listen for
+    # mapping changes. Modifying mapping that is set to proxy will trigger
+    # dataset re-resolving.
+    def setMapping(self, mapping):
+        if self._mapping:
+            self._mapping.mappingChanged.disconnect(self.handleMappingChanged)
+
+        self._mapping = mapping
+
+        if self._mapping:
+            self._mapping.mappingChanged.connect(self.handleMappingChanged)
+
+        self.resolveDataSet()
+
+    def mapping(self):
+        return self._mapping.data()
+
+    @Slot(int, int)
+    def handleItemsAdded(self, index, count):
+        # Resolve new items
+        self.resolveDataSet()
+
+    @Slot()
+    def handleDataCleared(self):
+        # Data cleared, reset array
+        self.resetArray(None)
+
+    @Slot()
+    def handleMappingChanged(self):
+        self.resolveDataSet()
+
+    # Resolve entire dataset into QBarDataArray.
+    def resolveDataSet(self):
+        # If we have no data or mapping, or the categories are not defined,
+        # simply clear the array
+        if (not self._dataSet or not self._mapping
+                or not self._mapping.rowCategories()
+                or not self._mapping.columnCategories()):
+            self.resetArray()
+            return
+
+        itemList = self._dataSet.itemList()
+
+        rowIndex = self._mapping.rowIndex()
+        columnIndex = self._mapping.columnIndex()
+        valueIndex = self._mapping.valueIndex()
+        rowList = self._mapping.rowCategories()
+        columnList = self._mapping.columnCategories()
+
+        # Sort values into rows and columns
+        itemValueMap = {}
+        for item in itemList:
+            key = str(item[rowIndex])
+            v = itemValueMap.get(key)
+            if not v:
+                v = {}
+                itemValueMap[key] = v
+            v[str(item[columnIndex])] = float(item[valueIndex])
+
+        # Create a new data array in format the parent class understands
+        newProxyArray = []
+        for rowKey in rowList:
+            newProxyRow = []
+            for i in range(0, len(columnList)):
+                item = QBarDataItem(itemValueMap[rowKey][columnList[i]])
+                newProxyRow.append(item)
+            newProxyArray.append(newProxyRow)
+
+        # Finally, reset the data array in the parent class
+        self.resetArray(newProxyArray)
diff --git a/examples/graphs/3d/widgetgallery/variantdataset.py b/examples/graphs/3d/widgetgallery/variantdataset.py
new file mode 100644 (file)
index 0000000..752bc38
--- /dev/null
@@ -0,0 +1,39 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtCore import QObject, Signal
+
+
+class VariantDataSet(QObject):
+
+    itemsAdded = Signal(int, int)
+    dataCleared = Signal()
+
+    def __init__(self):
+        super().__init__()
+        self._variantData = []
+
+    def clear(self):
+        for item in self._variantData:
+            item.clear()
+            del item
+
+        self._variantData.clear()
+        self.dataCleared.emit()
+
+    def addItem(self, item):
+        self._variantData.append(item)
+        addIndex = len(self._variantData)
+
+        self.itemsAdded.emit(addIndex, 1)
+        return addIndex
+
+    def addItems(self, itemList):
+        newCount = len(itemList)
+        addIndex = len(self._variantData)
+        self._variantData.extend(itemList)
+        self.itemsAdded.emit(addIndex, newCount)
+        return addIndex
+
+    def itemList(self):
+        return self._variantData
diff --git a/examples/graphs/3d/widgetgallery/widgetgallery.pyproject b/examples/graphs/3d/widgetgallery/widgetgallery.pyproject
new file mode 100644 (file)
index 0000000..581b214
--- /dev/null
@@ -0,0 +1,29 @@
+{
+    "files": ["main.py",
+              "axesinputhandler.py",
+              "bargraph.py",
+              "custominputhandler.py",
+              "graphmodifier.py",
+              "highlightseries.py",
+              "rainfalldata.py",
+              "scatterdatamodifier.py",
+              "scattergraph.py",
+              "surfacegraph.py",
+              "surfacegraphmodifier.py",
+              "topographicseries.py",
+              "variantbardatamapping.py",
+              "variantbardataproxy.py",
+              "variantdataset.py",
+              "data/layer_1.png",
+              "data/layer_2.png",
+              "data/layer_3.png",
+              "data/license.txt",
+              "data/maptexture.jpg",
+              "data/narrowarrow.mesh",
+              "data/oilrig.mesh",
+              "data/pipe.mesh",
+              "data/raindata.txt",
+              "data/refinery.mesh",
+              "data/topography.png"
+]
+}
diff --git a/examples/graphs/minimalsurfacegraph/doc/minimalsurfacegraph.rst b/examples/graphs/minimalsurfacegraph/doc/minimalsurfacegraph.rst
deleted file mode 100644 (file)
index bfc7a04..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Minimal Surface Example
-=======================
-
-The example shows the minimal code to create a surface.
diff --git a/examples/graphs/minimalsurfacegraph/main.py b/examples/graphs/minimalsurfacegraph/main.py
deleted file mode 100644 (file)
index 5fb4b44..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-import sys
-
-from PySide6.QtCore import QSize
-from PySide6.QtGui import QVector3D
-from PySide6.QtGraphs import (Q3DSurface, QSurfaceDataItem,
-                              QSurface3DSeries)
-from PySide6.QtWidgets import QApplication
-from PySide6.QtQuickWidgets import QQuickWidget
-
-
-DESCRIPTION = """Minimal Qt Graphs Surface Example
-
-Use the mouse wheel to zoom. Rotate using the right mouse button.
-"""
-
-
-if __name__ == '__main__':
-    app = QApplication(sys.argv)
-
-    print(DESCRIPTION)
-
-    surface = Q3DSurface()
-    axis = surface.axisX()
-    axis.setTitle("X")
-    axis.setTitleVisible(True)
-    axis = surface.axisY()
-    axis.setTitle("Y")
-    axis.setTitleVisible(True)
-    axis = surface.axisZ()
-    axis.setTitle("Z")
-    axis.setTitleVisible(True)
-
-    data = []
-    data_row1 = [QSurfaceDataItem(QVector3D(0, 0.1, 0.5)),
-                 QSurfaceDataItem(QVector3D(1, 0.5, 0.5))]
-    data.append(data_row1)
-    data_row2 = [QSurfaceDataItem(QVector3D(0, 1.8, 1)),
-                 QSurfaceDataItem(QVector3D(1, 1.2, 1))]
-    data.append(data_row2)
-
-    series = QSurface3DSeries()
-    series.dataProxy().resetArray(data)
-    surface.addSeries(series)
-
-    available_height = app.primaryScreen().availableGeometry().height()
-    width = available_height * 4 / 5
-    surface.resize(QSize(width, width))
-    surface.setResizeMode(QQuickWidget.SizeRootObjectToView)
-    surface.show()
-
-    sys.exit(app.exec())
diff --git a/examples/graphs/widgetgallery/axesinputhandler.py b/examples/graphs/widgetgallery/axesinputhandler.py
deleted file mode 100644 (file)
index 768fac5..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from enum import Enum
-from math import sin, cos, degrees
-
-from PySide6.QtCore import Qt
-from PySide6.QtGraphs import QAbstract3DGraph, Q3DInputHandler
-
-
-class InputState(Enum):
-    StateNormal = 0
-    StateDraggingX = 1
-    StateDraggingZ = 2
-    StateDraggingY = 3
-
-
-class AxesInputHandler(Q3DInputHandler):
-
-    def __init__(self, graph, parent=None):
-        super().__init__(parent)
-        self._mousePressed = False
-        self._state = InputState.StateNormal
-        self._axisX = None
-        self._axisZ = None
-        self._axisY = None
-        self._speedModifier = 15.0
-
-        # Connect to the item selection signal from graph
-        graph.selectedElementChanged.connect(self.handleElementSelected)
-
-    def setAxes(self, axisX, axisZ, axisY):
-        self._axisX = axisX
-        self._axisZ = axisZ
-        self._axisY = axisY
-
-    def setDragSpeedModifier(self, modifier):
-        self._speedModifier = modifier
-
-    def mousePressEvent(self, event, mousePos):
-        super().mousePressEvent(event, mousePos)
-        if Qt.LeftButton == event.button():
-            self._mousePressed = True
-
-    def mouseMoveEvent(self, event, mousePos):
-        # Check if we're trying to drag axis label
-        if self._mousePressed and self._state != InputState.StateNormal:
-            self.setPreviousInputPos(self.inputPosition())
-            self.setInputPosition(mousePos)
-            self.handleAxisDragging()
-        else:
-            super().mouseMoveEvent(event, mousePos)
-
-    def mouseReleaseEvent(self, event, mousePos):
-        super().mouseReleaseEvent(event, mousePos)
-        self._mousePressed = False
-        self._state = InputState.StateNormal
-
-    def handleElementSelected(self, type):
-        if type == QAbstract3DGraph.ElementAxisXLabel:
-            self._state = InputState.StateDraggingX
-        elif type == QAbstract3DGraph.ElementAxisYLabel:
-            self._state = InputState.StateDraggingY
-        elif type == QAbstract3DGraph.ElementAxisZLabel:
-            self._state = InputState.StateDraggingZ
-        else:
-            self._state = InputState.StateNormal
-
-    def handleAxisDragging(self):
-        distance = 0.0
-        # Get scene orientation from active camera
-        ac = self.scene().activeCamera()
-        xRotation = ac.xRotation()
-        yRotation = ac.yRotation()
-
-        # Calculate directional drag multipliers based on rotation
-        xMulX = cos(degrees(xRotation))
-        xMulY = sin(degrees(xRotation))
-        zMulX = sin(degrees(xRotation))
-        zMulY = cos(degrees(xRotation))
-
-        # Get the drag amount
-        move = self.inputPosition() - self.previousInputPos()
-
-        # Flip the effect of y movement if we're viewing from below
-        yMove = -move.y() if yRotation < 0 else move.y()
-
-        # Adjust axes
-        if self._state == InputState.StateDraggingX:
-            distance = (move.x() * xMulX - yMove * xMulY) / self._speedModifier
-            self._axisX.setRange(self._axisX.min() - distance,
-                                 self._axisX.max() - distance)
-        elif self._state == InputState.StateDraggingZ:
-            distance = (move.x() * zMulX + yMove * zMulY) / self._speedModifier
-            self._axisZ.setRange(self._axisZ.min() + distance,
-                                 self._axisZ.max() + distance)
-        elif self._state == InputState.StateDraggingY:
-            # No need to use adjusted y move here
-            distance = move.y() / self._speedModifier
-            self._axisY.setRange(self._axisY.min() + distance,
-                                 self._axisY.max() + distance)
diff --git a/examples/graphs/widgetgallery/bargraph.py b/examples/graphs/widgetgallery/bargraph.py
deleted file mode 100644 (file)
index db0dd8e..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from graphmodifier import GraphModifier
-
-from PySide6.QtCore import QObject, Qt
-from PySide6.QtGui import QFont
-from PySide6.QtWidgets import (QButtonGroup, QCheckBox, QComboBox, QFontComboBox,
-                               QLabel, QPushButton, QHBoxLayout, QSizePolicy,
-                               QRadioButton, QSlider, QVBoxLayout, QWidget)
-from PySide6.QtQuickWidgets import QQuickWidget
-from PySide6.QtGraphs import (QAbstract3DGraph, QAbstract3DSeries, Q3DBars)
-
-
-class BarGraph(QObject):
-
-    def __init__(self, minimum_graph_size, maximum_graph_size):
-        super().__init__()
-        self._barsGraph = Q3DBars()
-        self._barsWidget = QWidget()
-        hLayout = QHBoxLayout(self._barsWidget)
-        self._barsGraph.setMinimumSize(minimum_graph_size)
-        self._barsGraph.setMaximumSize(maximum_graph_size)
-        self._barsGraph.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
-        self._barsGraph.setFocusPolicy(Qt.StrongFocus)
-        self._barsGraph.setResizeMode(QQuickWidget.SizeRootObjectToView)
-        hLayout.addWidget(self._barsGraph, 1)
-
-        vLayout = QVBoxLayout()
-        hLayout.addLayout(vLayout)
-
-        themeList = QComboBox(self._barsWidget)
-        themeList.addItem("Qt")
-        themeList.addItem("Primary Colors")
-        themeList.addItem("Digia")
-        themeList.addItem("Stone Moss")
-        themeList.addItem("Army Blue")
-        themeList.addItem("Retro")
-        themeList.addItem("Ebony")
-        themeList.addItem("Isabelle")
-        themeList.setCurrentIndex(0)
-
-        labelButton = QPushButton(self._barsWidget)
-        labelButton.setText("Change label style")
-
-        smoothCheckBox = QCheckBox(self._barsWidget)
-        smoothCheckBox.setText("Smooth bars")
-        smoothCheckBox.setChecked(False)
-
-        barStyleList = QComboBox(self._barsWidget)
-        barStyleList.addItem("Bar", QAbstract3DSeries.MeshBar)
-        barStyleList.addItem("Pyramid", QAbstract3DSeries.MeshPyramid)
-        barStyleList.addItem("Cone", QAbstract3DSeries.MeshCone)
-        barStyleList.addItem("Cylinder", QAbstract3DSeries.MeshCylinder)
-        barStyleList.addItem("Bevel bar", QAbstract3DSeries.MeshBevelBar)
-        barStyleList.addItem("Sphere", QAbstract3DSeries.MeshSphere)
-        barStyleList.setCurrentIndex(4)
-
-        cameraButton = QPushButton(self._barsWidget)
-        cameraButton.setText("Change camera preset")
-
-        zoomToSelectedButton = QPushButton(self._barsWidget)
-        zoomToSelectedButton.setText("Zoom to selected bar")
-
-        selectionModeList = QComboBox(self._barsWidget)
-        selectionModeList.addItem("None", QAbstract3DGraph.SelectionNone)
-        selectionModeList.addItem("Bar", QAbstract3DGraph.SelectionItem)
-        selectionModeList.addItem("Row", QAbstract3DGraph.SelectionRow)
-        sel = QAbstract3DGraph.SelectionItemAndRow
-        selectionModeList.addItem("Bar and Row", sel)
-        selectionModeList.addItem("Column", QAbstract3DGraph.SelectionColumn)
-        sel = QAbstract3DGraph.SelectionItemAndColumn
-        selectionModeList.addItem("Bar and Column", sel)
-        sel = QAbstract3DGraph.SelectionRowAndColumn
-        selectionModeList.addItem("Row and Column", sel)
-        sel = QAbstract3DGraph.SelectionItemRowAndColumn
-        selectionModeList.addItem("Bar, Row and Column", sel)
-        sel = QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionRow
-        selectionModeList.addItem("Slice into Row", sel)
-        sel = QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionItemAndRow
-        selectionModeList.addItem("Slice into Row and Item", sel)
-        sel = QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionColumn
-        selectionModeList.addItem("Slice into Column", sel)
-        sel = (QAbstract3DGraph.SelectionSlice
-               | QAbstract3DGraph.SelectionItemAndColumn)
-        selectionModeList.addItem("Slice into Column and Item", sel)
-        sel = (QAbstract3DGraph.SelectionItemRowAndColumn
-               | QAbstract3DGraph.SelectionMultiSeries)
-        selectionModeList.addItem("Multi: Bar, Row, Col", sel)
-        sel = (QAbstract3DGraph.SelectionSlice
-               | QAbstract3DGraph.SelectionItemAndRow
-               | QAbstract3DGraph.SelectionMultiSeries)
-        selectionModeList.addItem("Multi, Slice: Row, Item", sel)
-        sel = (QAbstract3DGraph.SelectionSlice
-               | QAbstract3DGraph.SelectionItemAndColumn
-               | QAbstract3DGraph.SelectionMultiSeries)
-        selectionModeList.addItem("Multi, Slice: Col, Item", sel)
-        selectionModeList.setCurrentIndex(1)
-
-        backgroundCheckBox = QCheckBox(self._barsWidget)
-        backgroundCheckBox.setText("Show background")
-        backgroundCheckBox.setChecked(False)
-
-        gridCheckBox = QCheckBox(self._barsWidget)
-        gridCheckBox.setText("Show grid")
-        gridCheckBox.setChecked(True)
-
-        seriesCheckBox = QCheckBox(self._barsWidget)
-        seriesCheckBox.setText("Show second series")
-        seriesCheckBox.setChecked(False)
-
-        reverseValueAxisCheckBox = QCheckBox(self._barsWidget)
-        reverseValueAxisCheckBox.setText("Reverse value axis")
-        reverseValueAxisCheckBox.setChecked(False)
-
-        reflectionCheckBox = QCheckBox(self._barsWidget)
-        reflectionCheckBox.setText("Show reflections")
-        reflectionCheckBox.setChecked(False)
-
-        rotationSliderX = QSlider(Qt.Horizontal, self._barsWidget)
-        rotationSliderX.setTickInterval(30)
-        rotationSliderX.setTickPosition(QSlider.TicksBelow)
-        rotationSliderX.setMinimum(-180)
-        rotationSliderX.setValue(0)
-        rotationSliderX.setMaximum(180)
-        rotationSliderY = QSlider(Qt.Horizontal, self._barsWidget)
-        rotationSliderY.setTickInterval(15)
-        rotationSliderY.setTickPosition(QSlider.TicksAbove)
-        rotationSliderY.setMinimum(-90)
-        rotationSliderY.setValue(0)
-        rotationSliderY.setMaximum(90)
-
-        fontSizeSlider = QSlider(Qt.Horizontal, self._barsWidget)
-        fontSizeSlider.setTickInterval(10)
-        fontSizeSlider.setTickPosition(QSlider.TicksBelow)
-        fontSizeSlider.setMinimum(1)
-        fontSizeSlider.setValue(30)
-        fontSizeSlider.setMaximum(100)
-
-        fontList = QFontComboBox(self._barsWidget)
-        fontList.setCurrentFont(QFont("Times New Roman"))
-
-        shadowQuality = QComboBox(self._barsWidget)
-        shadowQuality.addItem("None")
-        shadowQuality.addItem("Low")
-        shadowQuality.addItem("Medium")
-        shadowQuality.addItem("High")
-        shadowQuality.addItem("Low Soft")
-        shadowQuality.addItem("Medium Soft")
-        shadowQuality.addItem("High Soft")
-        shadowQuality.setCurrentIndex(5)
-
-        rangeList = QComboBox(self._barsWidget)
-        rangeList.addItem("2015")
-        rangeList.addItem("2016")
-        rangeList.addItem("2017")
-        rangeList.addItem("2018")
-        rangeList.addItem("2019")
-        rangeList.addItem("2020")
-        rangeList.addItem("2021")
-        rangeList.addItem("2022")
-        rangeList.addItem("All")
-        rangeList.setCurrentIndex(8)
-
-        axisTitlesVisibleCB = QCheckBox(self._barsWidget)
-        axisTitlesVisibleCB.setText("Axis titles visible")
-        axisTitlesVisibleCB.setChecked(True)
-
-        axisTitlesFixedCB = QCheckBox(self._barsWidget)
-        axisTitlesFixedCB.setText("Axis titles fixed")
-        axisTitlesFixedCB.setChecked(True)
-
-        axisLabelRotationSlider = QSlider(Qt.Horizontal, self._barsWidget)
-        axisLabelRotationSlider.setTickInterval(10)
-        axisLabelRotationSlider.setTickPosition(QSlider.TicksBelow)
-        axisLabelRotationSlider.setMinimum(0)
-        axisLabelRotationSlider.setValue(30)
-        axisLabelRotationSlider.setMaximum(90)
-
-        modeGroup = QButtonGroup(self._barsWidget)
-        modeWeather = QRadioButton("Temperature Data", self._barsWidget)
-        modeWeather.setChecked(True)
-        modeCustomProxy = QRadioButton("Custom Proxy Data", self._barsWidget)
-        modeGroup.addButton(modeWeather)
-        modeGroup.addButton(modeCustomProxy)
-
-        vLayout.addWidget(QLabel("Rotate horizontally"))
-        vLayout.addWidget(rotationSliderX, 0, Qt.AlignTop)
-        vLayout.addWidget(QLabel("Rotate vertically"))
-        vLayout.addWidget(rotationSliderY, 0, Qt.AlignTop)
-        vLayout.addWidget(labelButton, 0, Qt.AlignTop)
-        vLayout.addWidget(cameraButton, 0, Qt.AlignTop)
-        vLayout.addWidget(zoomToSelectedButton, 0, Qt.AlignTop)
-        vLayout.addWidget(backgroundCheckBox)
-        vLayout.addWidget(gridCheckBox)
-        vLayout.addWidget(smoothCheckBox)
-        vLayout.addWidget(reflectionCheckBox)
-        vLayout.addWidget(seriesCheckBox)
-        vLayout.addWidget(reverseValueAxisCheckBox)
-        vLayout.addWidget(axisTitlesVisibleCB)
-        vLayout.addWidget(axisTitlesFixedCB)
-        vLayout.addWidget(QLabel("Show year"))
-        vLayout.addWidget(rangeList)
-        vLayout.addWidget(QLabel("Change bar style"))
-        vLayout.addWidget(barStyleList)
-        vLayout.addWidget(QLabel("Change selection mode"))
-        vLayout.addWidget(selectionModeList)
-        vLayout.addWidget(QLabel("Change theme"))
-        vLayout.addWidget(themeList)
-        vLayout.addWidget(QLabel("Adjust shadow quality"))
-        vLayout.addWidget(shadowQuality)
-        vLayout.addWidget(QLabel("Change font"))
-        vLayout.addWidget(fontList)
-        vLayout.addWidget(QLabel("Adjust font size"))
-        vLayout.addWidget(fontSizeSlider)
-        vLayout.addWidget(QLabel("Axis label rotation"))
-        vLayout.addWidget(axisLabelRotationSlider, 0, Qt.AlignTop)
-        vLayout.addWidget(modeWeather, 0, Qt.AlignTop)
-        vLayout.addWidget(modeCustomProxy, 1, Qt.AlignTop)
-
-        self._modifier = GraphModifier(self._barsGraph, self)
-
-        rotationSliderX.valueChanged.connect(self._modifier.rotateX)
-        rotationSliderY.valueChanged.connect(self._modifier.rotateY)
-
-        labelButton.clicked.connect(self._modifier.changeLabelBackground)
-        cameraButton.clicked.connect(self._modifier.changePresetCamera)
-        zoomToSelectedButton.clicked.connect(self._modifier.zoomToSelectedBar)
-
-        backgroundCheckBox.stateChanged.connect(self._modifier.setBackgroundEnabled)
-        gridCheckBox.stateChanged.connect(self._modifier.setGridEnabled)
-        smoothCheckBox.stateChanged.connect(self._modifier.setSmoothBars)
-        seriesCheckBox.stateChanged.connect(self._modifier.setSeriesVisibility)
-        reverseValueAxisCheckBox.stateChanged.connect(self._modifier.setReverseValueAxis)
-        reflectionCheckBox.stateChanged.connect(self._modifier.setReflection)
-
-        self._modifier.backgroundEnabledChanged.connect(backgroundCheckBox.setChecked)
-        self._modifier.gridEnabledChanged.connect(gridCheckBox.setChecked)
-
-        rangeList.currentIndexChanged.connect(self._modifier.changeRange)
-
-        barStyleList.currentIndexChanged.connect(self._modifier.changeStyle)
-
-        selectionModeList.currentIndexChanged.connect(self._modifier.changeSelectionMode)
-
-        themeList.currentIndexChanged.connect(self._modifier.changeTheme)
-
-        shadowQuality.currentIndexChanged.connect(self._modifier.changeShadowQuality)
-
-        self._modifier.shadowQualityChanged.connect(shadowQuality.setCurrentIndex)
-        self._barsGraph.shadowQualityChanged.connect(self._modifier.shadowQualityUpdatedByVisual)
-
-        fontSizeSlider.valueChanged.connect(self._modifier.changeFontSize)
-        fontList.currentFontChanged.connect(self._modifier.changeFont)
-
-        self._modifier.fontSizeChanged.connect(fontSizeSlider.setValue)
-        self._modifier.fontChanged.connect(fontList.setCurrentFont)
-
-        axisTitlesVisibleCB.stateChanged.connect(self._modifier.setAxisTitleVisibility)
-        axisTitlesFixedCB.stateChanged.connect(self._modifier.setAxisTitleFixed)
-        axisLabelRotationSlider.valueChanged.connect(self._modifier.changeLabelRotation)
-
-        modeWeather.toggled.connect(self._modifier.setDataModeToWeather)
-        modeCustomProxy.toggled.connect(self._modifier.setDataModeToCustom)
-        modeWeather.toggled.connect(seriesCheckBox.setEnabled)
-        modeWeather.toggled.connect(rangeList.setEnabled)
-        modeWeather.toggled.connect(axisTitlesVisibleCB.setEnabled)
-        modeWeather.toggled.connect(axisTitlesFixedCB.setEnabled)
-        modeWeather.toggled.connect(axisLabelRotationSlider.setEnabled)
-
-    def barsWidget(self):
-        return self._barsWidget
diff --git a/examples/graphs/widgetgallery/custominputhandler.py b/examples/graphs/widgetgallery/custominputhandler.py
deleted file mode 100644 (file)
index 458ef62..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from enum import Enum
-from math import sin, cos, degrees
-
-from PySide6.QtCore import Qt
-from PySide6.QtGraphs import (QAbstract3DGraph, Q3DInputHandler)
-
-
-class InputState(Enum):
-    StateNormal = 0
-    StateDraggingX = 1
-    StateDraggingZ = 2
-    StateDraggingY = 3
-
-
-class CustomInputHandler(Q3DInputHandler):
-
-    def __init__(self, graph, parent=None):
-        super().__init__(parent)
-        self._highlight = None
-        self._mousePressed = False
-        self._state = InputState.StateNormal
-        self._axisX = None
-        self._axisY = None
-        self._axisZ = None
-        self._speedModifier = 20.0
-        self._aspectRatio = 0.0
-        self._axisXMinValue = 0.0
-        self._axisXMaxValue = 0.0
-        self._axisXMinRange = 0.0
-        self._axisZMinValue = 0.0
-        self._axisZMaxValue = 0.0
-        self._axisZMinRange = 0.0
-        self._areaMinValue = 0.0
-        self._areaMaxValue = 0.0
-
-        # Connect to the item selection signal from graph
-        graph.selectedElementChanged.connect(self.handleElementSelected)
-
-    def setAspectRatio(self, ratio):
-        self._aspectRatio = ratio
-
-    def setHighlightSeries(self, series):
-        self._highlight = series
-
-    def setDragSpeedModifier(self, modifier):
-        self._speedModifier = modifier
-
-    def setLimits(self, min, max, minRange):
-        self._areaMinValue = min
-        self._areaMaxValue = max
-        self._axisXMinValue = self._areaMinValue
-        self._axisXMaxValue = self._areaMaxValue
-        self._axisZMinValue = self._areaMinValue
-        self._axisZMaxValue = self._areaMaxValue
-        self._axisXMinRange = minRange
-        self._axisZMinRange = minRange
-
-    def setAxes(self, axisX, axisY, axisZ):
-        self._axisX = axisX
-        self._axisY = axisY
-        self._axisZ = axisZ
-
-    def mousePressEvent(self, event, mousePos):
-        if Qt.LeftButton == event.button():
-            self._highlight.setVisible(False)
-            self._mousePressed = True
-        super().mousePressEvent(event, mousePos)
-
-    def wheelEvent(self, event):
-        delta = float(event.angleDelta().y())
-
-        self._axisXMinValue += delta
-        self._axisXMaxValue -= delta
-        self._axisZMinValue += delta
-        self._axisZMaxValue -= delta
-        self.checkConstraints()
-
-        y = (self._axisXMaxValue - self._axisXMinValue) * self._aspectRatio
-
-        self._axisX.setRange(self._axisXMinValue, self._axisXMaxValue)
-        self._axisY.setRange(100.0, y)
-        self._axisZ.setRange(self._axisZMinValue, self._axisZMaxValue)
-
-    def mouseMoveEvent(self, event, mousePos):
-        # Check if we're trying to drag axis label
-        if self._mousePressed and self._state != InputState.StateNormal:
-            self.setPreviousInputPos(self.inputPosition())
-            self.setInputPosition(mousePos)
-            self.handleAxisDragging()
-        else:
-            super().mouseMoveEvent(event, mousePos)
-
-    def mouseReleaseEvent(self, event, mousePos):
-        super().mouseReleaseEvent(event, mousePos)
-        self._mousePressed = False
-        self._state = InputState.StateNormal
-
-    def handleElementSelected(self, type):
-        if type == QAbstract3DGraph.ElementAxisXLabel:
-            self._state = InputState.StateDraggingX
-        elif type == QAbstract3DGraph.ElementAxisZLabel:
-            self._state = InputState.StateDraggingZ
-        else:
-            self._state = InputState.StateNormal
-
-    def handleAxisDragging(self):
-        distance = 0.0
-
-        # Get scene orientation from active camera
-        xRotation = self.scene().activeCamera().xRotation()
-
-        # Calculate directional drag multipliers based on rotation
-        xMulX = cos(degrees(xRotation))
-        xMulY = sin(degrees(xRotation))
-        zMulX = xMulY
-        zMulY = xMulX
-
-        # Get the drag amount
-        move = self.inputPosition() - self.previousInputPos()
-
-        # Adjust axes
-        if self._state == InputState.StateDraggingX:
-            distance = (move.x() * xMulX - move.y() * xMulY) * self._speedModifier
-            self._axisXMinValue -= distance
-            self._axisXMaxValue -= distance
-            if self._axisXMinValue < self._areaMinValue:
-                dist = self._axisXMaxValue - self._axisXMinValue
-                self._axisXMinValue = self._areaMinValue
-                self._axisXMaxValue = self._axisXMinValue + dist
-
-            if self._axisXMaxValue > self._areaMaxValue:
-                dist = self._axisXMaxValue - self._axisXMinValue
-                self._axisXMaxValue = self._areaMaxValue
-                self._axisXMinValue = self._axisXMaxValue - dist
-
-            self._axisX.setRange(self._axisXMinValue, self._axisXMaxValue)
-        elif self._state == InputState.StateDraggingZ:
-            distance = (move.x() * zMulX + move.y() * zMulY) * self._speedModifier
-            self._axisZMinValue += distance
-            self._axisZMaxValue += distance
-            if self._axisZMinValue < self._areaMinValue:
-                dist = self._axisZMaxValue - self._axisZMinValue
-                self._axisZMinValue = self._areaMinValue
-                self._axisZMaxValue = self._axisZMinValue + dist
-
-            if self._axisZMaxValue > self._areaMaxValue:
-                dist = self._axisZMaxValue - self._axisZMinValue
-                self._axisZMaxValue = self._areaMaxValue
-                self._axisZMinValue = self._axisZMaxValue - dist
-
-            self._axisZ.setRange(self._axisZMinValue, self._axisZMaxValue)
-
-    def checkConstraints(self):
-        if self._axisXMinValue < self._areaMinValue:
-            self._axisXMinValue = self._areaMinValue
-        if self._axisXMaxValue > self._areaMaxValue:
-            self._axisXMaxValue = self._areaMaxValue
-        # Don't allow too much zoom in
-        range = self._axisXMaxValue - self._axisXMinValue
-        if range < self._axisXMinRange:
-            adjust = (self._axisXMinRange - range) / 2.0
-            self._axisXMinValue -= adjust
-            self._axisXMaxValue += adjust
-
-        if self._axisZMinValue < self._areaMinValue:
-            self._axisZMinValue = self._areaMinValue
-        if self._axisZMaxValue > self._areaMaxValue:
-            self._axisZMaxValue = self._areaMaxValue
-        # Don't allow too much zoom in
-        range = self._axisZMaxValue - self._axisZMinValue
-        if range < self._axisZMinRange:
-            adjust = (self._axisZMinRange - range) / 2.0
-            self._axisZMinValue -= adjust
-            self._axisZMaxValue += adjust
diff --git a/examples/graphs/widgetgallery/data/layer_1.png b/examples/graphs/widgetgallery/data/layer_1.png
deleted file mode 100644 (file)
index 9138c71..0000000
Binary files a/examples/graphs/widgetgallery/data/layer_1.png and /dev/null differ
diff --git a/examples/graphs/widgetgallery/data/layer_2.png b/examples/graphs/widgetgallery/data/layer_2.png
deleted file mode 100644 (file)
index 61631ae..0000000
Binary files a/examples/graphs/widgetgallery/data/layer_2.png and /dev/null differ
diff --git a/examples/graphs/widgetgallery/data/layer_3.png b/examples/graphs/widgetgallery/data/layer_3.png
deleted file mode 100644 (file)
index 066ffbe..0000000
Binary files a/examples/graphs/widgetgallery/data/layer_3.png and /dev/null differ
diff --git a/examples/graphs/widgetgallery/data/license.txt b/examples/graphs/widgetgallery/data/license.txt
deleted file mode 100644 (file)
index 749daf3..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-License information regarding the data obtained from National Land Survey of
-Finland http://www.maanmittauslaitos.fi/en
-- topographic model from Elevation model 2 m (U4421B, U4421D, U4422A and
-  U4422C) 08/2014
-- map image extracted from Topographic map raster 1:50 000 (U442) 08/2014
-
-National Land Survey open data licence - version 1.0 - 1 May 2012
-
-1. General information
-
-The National Land Survey of Finland (hereinafter the Licensor), as the holder
-of the immaterial rights to the data, has granted on the terms mentioned below
-the right to use a copy (hereinafter data or dataset(s)) of the data (or a part
-of it).
-
-The Licensee is a natural or legal person who makes use of the data covered by
-this licence. The Licensee accepts the terms of this licence by receiving the
-dataset(s) covered by the licence.
-
-This Licence agreement does not create a co-operation or business relationship
-between the Licensee and the Licensor.
-
-2. Terms of the licence
-
-2.1. Right of use
-
-This licence grants a worldwide, free of charge and irrevocable parallel right
-of use to open data. According to the terms of the licence, data received by
-the Licensee can be freely:
- - copied, distributed and published,
- - modified and utilised commercially and non-commercially,
- - inserted into other products and
- - used as a part of a software application or service.
-
-2.2. Duties and responsibilities of the Licensee
-
-Through reasonable means suitable to the distribution medium or method which is
-used in conjunction with a product containing data or a service utilising data
-covered by this licence or while distributing data, the Licensee shall:
- - mention the name of the Licensor, the name of the dataset(s) and the time
-   when the National Land Survey has delivered the dataset(s) (e.g.: contains
-   data from the National Land Survey of Finland Topographic Database 06/2012)
- - provide a copy of this licence or a link to it, as well as
- - require third parties to provide the same information when granting rights
-   to copies of dataset(s) or products and services containing such data and
- - remove the name of the Licensor from the product or service, if required to
-   do so by the Licensor.
-
-The terms of this licence do not allow the Licensee to state in conjunction
-with the use of dataset(s) that the Licensor supports or recommends such use.
-
-2.3. Duties and responsibilities of the Licensor
-
-The Licensor shall ensure that
- - the Licensor has the right to grant rights to the dataset(s) in accordance
-   with this licence.
-
-The data has been licensed "as is" and the Licensor
- - shall not be held responsible for any errors or omissions in the data,
-   disclaims any warranty for the validity or up to date status of the data and
-   shall be free from liability for direct or consequential damages arising
-   from the use of data provided by the Licensor,
- - and is not obligated to ensure the continuous availability of the data, nor
-   to announce in advance the interruption or cessation of availability, and
-   the Licensor shall be free from liability for direct or consequential
-   damages arising from any such interruption or cessation.
-
-3. Jurisdiction
-
-Finnish law shall apply to this licence.
-
-4. Changes to this licence
-
-The Licensor may at any time change the terms of the licence or apply a
-different licence to the data. The terms of this licence shall, however, still
-apply to such data that has been received prior to the change of the terms of
-the licence or the licence itself.
diff --git a/examples/graphs/widgetgallery/data/maptexture.jpg b/examples/graphs/widgetgallery/data/maptexture.jpg
deleted file mode 100644 (file)
index ae5d66e..0000000
Binary files a/examples/graphs/widgetgallery/data/maptexture.jpg and /dev/null differ
diff --git a/examples/graphs/widgetgallery/data/narrowarrow.mesh b/examples/graphs/widgetgallery/data/narrowarrow.mesh
deleted file mode 100644 (file)
index 288867b..0000000
Binary files a/examples/graphs/widgetgallery/data/narrowarrow.mesh and /dev/null differ
diff --git a/examples/graphs/widgetgallery/data/oilrig.mesh b/examples/graphs/widgetgallery/data/oilrig.mesh
deleted file mode 100644 (file)
index 4a7baed..0000000
Binary files a/examples/graphs/widgetgallery/data/oilrig.mesh and /dev/null differ
diff --git a/examples/graphs/widgetgallery/data/pipe.mesh b/examples/graphs/widgetgallery/data/pipe.mesh
deleted file mode 100644 (file)
index 984b6d4..0000000
Binary files a/examples/graphs/widgetgallery/data/pipe.mesh and /dev/null differ
diff --git a/examples/graphs/widgetgallery/data/raindata.txt b/examples/graphs/widgetgallery/data/raindata.txt
deleted file mode 100644 (file)
index d955892..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-# Rainfall per month from 2010 to 2022 in Northern Finland (Oulu)
-# Format: year, month, rainfall
-2010,1, 0,
-2010,2, 3.4,
-2010,3, 52,
-2010,4, 33.8,
-2010,5, 45.6,
-2010,6, 43.8,
-2010,7, 104.6,
-2010,8, 105.4,
-2010,9, 107.2,
-2010,10,38.6,
-2010,11,17.8,
-2010,12,0,
-2011,1, 8.2,
-2011,2, 1.6,
-2011,3, 27.4,
-2011,4, 15.8,
-2011,5, 57.6,
-2011,6, 85.2,
-2011,7, 127,
-2011,8, 72.2,
-2011,9, 82.2,
-2011,10,62.4,
-2011,11,31.6,
-2011,12,53.8,
-2012,1, 0,
-2012,2, 5,
-2012,3, 32.4,
-2012,4, 57.6,
-2012,5, 71.4,
-2012,6, 60.8,
-2012,7, 109,
-2012,8, 43.6,
-2012,9, 79.4,
-2012,10,117.2,
-2012,11,59,
-2012,12,0.2,
-2013,1, 28,
-2013,2, 19,
-2013,3, 0,
-2013,4, 37.6,
-2013,5, 44.2,
-2013,6, 104.8,
-2013,7, 84.2,
-2013,8, 57.2,
-2013,9, 37.2,
-2013,10,64.6,
-2013,11,77.8,
-2013,12,92.8,
-2014,1, 23.8,
-2014,2, 23.6,
-2014,3, 15.4,
-2014,4, 13.2,
-2014,5, 36.4,
-2014,6, 26.4,
-2014,7, 95.8,
-2014,8, 81.8,
-2014,9, 13.8,
-2014,10,94.6,
-2014,11,44.6,
-2014,12,31,
-2015,1, 37.4,
-2015,2, 21,
-2015,3, 42,
-2015,4, 8.8,
-2015,5, 82.4,
-2015,6, 150,
-2015,7, 56.8,
-2015,8, 67.2,
-2015,9, 131.2,
-2015,10,38.4,
-2015,11,83.4,
-2015,12,47.8,
-2016,1, 12.4,
-2016,2, 34.8,
-2016,3, 29,
-2016,4, 40.4,
-2016,5, 32.4,
-2016,6, 80.2,
-2016,7, 102.6,
-2016,8, 95.6,
-2016,9, 40.2,
-2016,10,7.8,
-2016,11,39.6,
-2016,12,8.8,
-2017,1, 9.4,
-2017,2, 6.6,
-2017,3, 29,
-2017,4, 46.2,
-2017,5, 43.2,
-2017,6, 25.2,
-2017,7, 72.4,
-2017,8, 58.8,
-2017,9, 68.8,
-2017,10,45.8,
-2017,11,36.8,
-2017,12,29.6,
-2018,1, 19.8,
-2018,2, 0.8,
-2018,3, 4,
-2018,4, 23.2,
-2018,5, 13.2,
-2018,6, 62.8,
-2018,7, 33,
-2018,8, 96.6,
-2018,9, 72.6,
-2018,10,48.8,
-2018,11,31.8,
-2018,12,12.8,
-2019,1, 0.2,
-2019,2, 24.8,
-2019,3, 32,
-2019,4, 8.8,
-2019,5, 71.4,
-2019,6, 65.8,
-2019,7, 17.6,
-2019,8, 90,
-2019,9, 50,
-2019,10,77,
-2019,11,27,
-2019,12,43.2,
-2020,1, 28.8,
-2020,2, 45,
-2020,3, 18.6,
-2020,4, 13,
-2020,5, 30.8,
-2020,6, 21.4,
-2020,7, 163.6,
-2020,8, 12,
-2020,9, 102.4,
-2020,10,133.2,
-2020,11,69.8,
-2020,12,40.6,
-2021,1, 0.4,
-2021,2, 21.6,
-2021,3, 24,
-2021,4, 51.4,
-2021,5, 76.4,
-2021,6, 29.2,
-2021,7, 36.4,
-2021,8, 116,
-2021,9, 72.4,
-2021,10,93.4,
-2021,11,21,
-2021,12,10.2,
-2022,1, 8.6,
-2022,2, 6.6,
-2022,3, 5.2,
-2022,4, 15.2,
-2022,5, 37.6,
-2022,6, 45,
-2022,7, 67.4,
-2022,8, 161.6,
-2022,9, 22.8,
-2022,10,75.2,
-2022,11,21.8,
-2022,12,0.2
diff --git a/examples/graphs/widgetgallery/data/refinery.mesh b/examples/graphs/widgetgallery/data/refinery.mesh
deleted file mode 100644 (file)
index a7e2493..0000000
Binary files a/examples/graphs/widgetgallery/data/refinery.mesh and /dev/null differ
diff --git a/examples/graphs/widgetgallery/data/topography.png b/examples/graphs/widgetgallery/data/topography.png
deleted file mode 100644 (file)
index 9349cdb..0000000
Binary files a/examples/graphs/widgetgallery/data/topography.png and /dev/null differ
diff --git a/examples/graphs/widgetgallery/doc/widgetgallery.rst b/examples/graphs/widgetgallery/doc/widgetgallery.rst
deleted file mode 100644 (file)
index 1470001..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-Widget Gallery
-==============
-
-
-Widget Gallery demonstrates all three graph types and some of their special
-features. The graphs have their own tabs in the application.
-
-
-.. image:: widgetgallery.webp
-   :width: 400
-   :alt: Widget Screenshot
diff --git a/examples/graphs/widgetgallery/doc/widgetgallery.webp b/examples/graphs/widgetgallery/doc/widgetgallery.webp
deleted file mode 100644 (file)
index eb57672..0000000
Binary files a/examples/graphs/widgetgallery/doc/widgetgallery.webp and /dev/null differ
diff --git a/examples/graphs/widgetgallery/graphmodifier.py b/examples/graphs/widgetgallery/graphmodifier.py
deleted file mode 100644 (file)
index 938e09c..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-
-from math import atan, degrees
-import numpy as np
-
-from PySide6.QtCore import QObject, QPropertyAnimation, Signal, Slot
-from PySide6.QtGui import QFont, QVector3D
-from PySide6.QtGraphs import (QAbstract3DGraph, QAbstract3DSeries,
-                              QBarDataItem, QBar3DSeries, QCategory3DAxis,
-                              QValue3DAxis, Q3DCamera, Q3DTheme)
-
-from rainfalldata import RainfallData
-
-# Set up data
-TEMP_OULU = np.array([
-    [-7.4, -2.4, 0.0, 3.0, 8.2, 11.6, 14.7, 15.4, 11.4, 4.2, 2.1, -2.3],  # 2015
-    [-13.4, -3.9, -1.8, 3.1, 10.6, 13.7, 17.8, 13.6, 10.7, 3.5, -3.1, -4.2],  # 2016
-    [-5.7, -6.7, -3.0, -0.1, 4.7, 12.4, 16.1, 14.1, 9.4, 3.0, -0.3, -3.2],  # 2017
-    [-6.4, -11.9, -7.4, 1.9, 11.4, 12.4, 21.5, 16.1, 11.0, 4.4, 2.1, -4.1],  # 2018
-    [-11.7, -6.1, -2.4, 3.9, 7.2, 14.5, 15.6, 14.4, 8.5, 2.0, -3.0, -1.5],  # 2019
-    [-2.1, -3.4, -1.8, 0.6, 7.0, 17.1, 15.6, 15.4, 11.1, 5.6, 1.9, -1.7],  # 2020
-    [-9.6, -11.6, -3.2, 2.4, 7.8, 17.3, 19.4, 14.2, 8.0, 5.2, -2.2, -8.6],  # 2021
-    [-7.3, -6.4, -1.8, 1.3, 8.1, 15.5, 17.6, 17.6, 9.1, 5.4, -1.5, -4.4]],  # 2022
-    np.float64)
-
-
-TEMP_HELSINKI = np.array([
-    [-2.0, -0.1, 1.8, 5.1, 9.7, 13.7, 16.3, 17.3, 12.7, 5.4, 4.6, 2.1],  # 2015
-    [-10.3, -0.6, 0.0, 4.9, 14.3, 15.7, 17.7, 16.0, 12.7, 4.6, -1.0, -0.9],  # 2016
-    [-2.9, -3.3, 0.7, 2.3, 9.9, 13.8, 16.1, 15.9, 11.4, 5.0, 2.7, 0.7],  # 2017
-    [-2.2, -8.4, -4.7, 5.0, 15.3, 15.8, 21.2, 18.2, 13.3, 6.7, 2.8, -2.0],  # 2018
-    [-6.2, -0.5, -0.3, 6.8, 10.6, 17.9, 17.5, 16.8, 11.3, 5.2, 1.8, 1.4],  # 2019
-    [1.9, 0.5, 1.7, 4.5, 9.5, 18.4, 16.5, 16.8, 13.0, 8.2, 4.4, 0.9],  # 2020
-    [-4.7, -8.1, -0.9, 4.5, 10.4, 19.2, 20.9, 15.4, 9.5, 8.0, 1.5, -6.7],  # 2021
-    [-3.3, -2.2, -0.2, 3.3, 9.6, 16.9, 18.1, 18.9, 9.2, 7.6, 2.3, -3.4]],  # 2022
-    np.float64)
-
-
-class GraphModifier(QObject):
-
-    shadowQualityChanged = Signal(int)
-    backgroundEnabledChanged = Signal(bool)
-    gridEnabledChanged = Signal(bool)
-    fontChanged = Signal(QFont)
-    fontSizeChanged = Signal(int)
-
-    def __init__(self, bargraph, parent):
-        super().__init__(parent)
-        self._graph = bargraph
-        self._temperatureAxis = QValue3DAxis()
-        self._yearAxis = QCategory3DAxis()
-        self._monthAxis = QCategory3DAxis()
-        self._primarySeries = QBar3DSeries()
-        self._secondarySeries = QBar3DSeries()
-        self._celsiusString = "°C"
-
-        self._xRotation = float(0)
-        self._yRotation = float(0)
-        self._fontSize = 30
-        self._segments = 4
-        self._subSegments = 3
-        self._minval = float(-20)
-        self._maxval = float(20)
-        self._barMesh = QAbstract3DSeries.MeshBevelBar
-        self._smooth = False
-        self._animationCameraX = QPropertyAnimation()
-        self._animationCameraY = QPropertyAnimation()
-        self._animationCameraZoom = QPropertyAnimation()
-        self._animationCameraTarget = QPropertyAnimation()
-        self._defaultAngleX = float(0)
-        self._defaultAngleY = float(0)
-        self._defaultZoom = float(0)
-        self._defaultTarget = []
-        self._customData = None
-
-        self._graph.setShadowQuality(QAbstract3DGraph.ShadowQualitySoftMedium)
-        theme = self._graph.activeTheme()
-        theme.setBackgroundEnabled(False)
-        theme.setFont(QFont("Times New Roman", self._fontSize))
-        theme.setLabelBackgroundEnabled(True)
-        self._graph.setMultiSeriesUniform(True)
-
-        self._months = ["January", "February", "March", "April", "May", "June",
-                        "July", "August", "September", "October", "November",
-                        "December"]
-        self._years = ["2015", "2016", "2017", "2018", "2019", "2020",
-                       "2021", "2022"]
-
-        self._temperatureAxis.setTitle("Average temperature")
-        self._temperatureAxis.setSegmentCount(self._segments)
-        self._temperatureAxis.setSubSegmentCount(self._subSegments)
-        self._temperatureAxis.setRange(self._minval, self._maxval)
-        self._temperatureAxis.setLabelFormat("%.1f " + self._celsiusString)
-        self._temperatureAxis.setLabelAutoRotation(30.0)
-        self._temperatureAxis.setTitleVisible(True)
-
-        self._yearAxis.setTitle("Year")
-        self._yearAxis.setLabelAutoRotation(30.0)
-        self._yearAxis.setTitleVisible(True)
-        self._monthAxis.setTitle("Month")
-        self._monthAxis.setLabelAutoRotation(30.0)
-        self._monthAxis.setTitleVisible(True)
-
-        self._graph.setValueAxis(self._temperatureAxis)
-        self._graph.setRowAxis(self._yearAxis)
-        self._graph.setColumnAxis(self._monthAxis)
-
-        format = "Oulu - @colLabel @rowLabel: @valueLabel"
-        self._primarySeries.setItemLabelFormat(format)
-        self._primarySeries.setMesh(QAbstract3DSeries.MeshBevelBar)
-        self._primarySeries.setMeshSmooth(False)
-
-        format = "Helsinki - @colLabel @rowLabel: @valueLabel"
-        self._secondarySeries.setItemLabelFormat(format)
-        self._secondarySeries.setMesh(QAbstract3DSeries.MeshBevelBar)
-        self._secondarySeries.setMeshSmooth(False)
-        self._secondarySeries.setVisible(False)
-
-        self._graph.addSeries(self._primarySeries)
-        self._graph.addSeries(self._secondarySeries)
-
-        self.changePresetCamera()
-
-        self.resetTemperatureData()
-
-        # Set up property animations for zooming to the selected bar
-        camera = self._graph.scene().activeCamera()
-        self._defaultAngleX = camera.xRotation()
-        self._defaultAngleY = camera.yRotation()
-        self._defaultZoom = camera.zoomLevel()
-        self._defaultTarget = camera.target()
-
-        self._animationCameraX.setTargetObject(camera)
-        self._animationCameraY.setTargetObject(camera)
-        self._animationCameraZoom.setTargetObject(camera)
-        self._animationCameraTarget.setTargetObject(camera)
-
-        self._animationCameraX.setPropertyName(b"xRotation")
-        self._animationCameraY.setPropertyName(b"yRotation")
-        self._animationCameraZoom.setPropertyName(b"zoomLevel")
-        self._animationCameraTarget.setPropertyName(b"target")
-
-        duration = 1700
-        self._animationCameraX.setDuration(duration)
-        self._animationCameraY.setDuration(duration)
-        self._animationCameraZoom.setDuration(duration)
-        self._animationCameraTarget.setDuration(duration)
-
-        # The zoom always first zooms out above the graph and then zooms in
-        zoomOutFraction = 0.3
-        self._animationCameraX.setKeyValueAt(zoomOutFraction, 0.0)
-        self._animationCameraY.setKeyValueAt(zoomOutFraction, 90.0)
-        self._animationCameraZoom.setKeyValueAt(zoomOutFraction, 50.0)
-        self._animationCameraTarget.setKeyValueAt(zoomOutFraction,
-                                                  QVector3D(0, 0, 0))
-        self._customData = RainfallData()
-
-    def resetTemperatureData(self):
-        # Create data arrays
-        dataSet = []
-        dataSet2 = []
-
-        for year in range(0, len(self._years)):
-            # Create a data row
-            dataRow = []
-            dataRow2 = []
-            for month in range(0, len(self._months)):
-                # Add data to the row
-                item = QBarDataItem()
-                item.setValue(TEMP_OULU[year][month])
-                dataRow.append(item)
-                item = QBarDataItem()
-                item.setValue(TEMP_HELSINKI[year][month])
-                dataRow2.append(item)
-
-            # Add the row to the set
-            dataSet.append(dataRow)
-            dataSet2.append(dataRow2)
-
-        # Add data to the data proxy (the data proxy assumes ownership of it)
-        self._primarySeries.dataProxy().resetArray(dataSet, self._years, self._months)
-        self._secondarySeries.dataProxy().resetArray(dataSet2, self._years, self._months)
-
-    @Slot(int)
-    def changeRange(self, range):
-        if range >= len(self._years):
-            self._yearAxis.setRange(0, len(self._years) - 1)
-        else:
-            self._yearAxis.setRange(range, range)
-
-    @Slot(int)
-    def changeStyle(self, style):
-        comboBox = self.sender()
-        if comboBox:
-            self._barMesh = comboBox.itemData(style)
-            self._primarySeries.setMesh(self._barMesh)
-            self._secondarySeries.setMesh(self._barMesh)
-            self._customData.customSeries().setMesh(self._barMesh)
-
-    def changePresetCamera(self):
-        self._animationCameraX.stop()
-        self._animationCameraY.stop()
-        self._animationCameraZoom.stop()
-        self._animationCameraTarget.stop()
-
-        # Restore camera target in case animation has changed it
-        self._graph.scene().activeCamera().setTarget(QVector3D(0.0, 0.0, 0.0))
-
-        self._preset = Q3DCamera.CameraPresetFront.value
-
-        camera = self._graph.scene().activeCamera()
-        camera.setCameraPreset(Q3DCamera.CameraPreset(self._preset))
-
-        self._preset += 1
-        if self._preset > Q3DCamera.CameraPresetDirectlyBelow.value:
-            self._preset = Q3DCamera.CameraPresetFrontLow.value
-
-    @Slot(int)
-    def changeTheme(self, theme):
-        currentTheme = self._graph.activeTheme()
-        currentTheme.setType(Q3DTheme.Theme(theme))
-        self.backgroundEnabledChanged.emit(currentTheme.isBackgroundEnabled())
-        self.gridEnabledChanged.emit(currentTheme.isGridEnabled())
-        self.fontChanged.emit(currentTheme.font())
-        self.fontSizeChanged.emit(currentTheme.font().pointSize())
-
-    def changeLabelBackground(self):
-        theme = self._graph.activeTheme()
-        theme.setLabelBackgroundEnabled(not theme.isLabelBackgroundEnabled())
-
-    @Slot(int)
-    def changeSelectionMode(self, selectionMode):
-        comboBox = self.sender()
-        if comboBox:
-            flags = comboBox.itemData(selectionMode)
-            self._graph.setSelectionMode(QAbstract3DGraph.SelectionFlags(flags))
-
-    def changeFont(self, font):
-        newFont = font
-        self._graph.activeTheme().setFont(newFont)
-
-    def changeFontSize(self, fontsize):
-        self._fontSize = fontsize
-        font = self._graph.activeTheme().font()
-        font.setPointSize(self._fontSize)
-        self._graph.activeTheme().setFont(font)
-
-    @Slot(QAbstract3DGraph.ShadowQuality)
-    def shadowQualityUpdatedByVisual(self, sq):
-        # Updates the UI component to show correct shadow quality
-        self.shadowQualityChanged.emit(sq.value)
-
-    @Slot(int)
-    def changeLabelRotation(self, rotation):
-        self._temperatureAxis.setLabelAutoRotation(float(rotation))
-        self._monthAxis.setLabelAutoRotation(float(rotation))
-        self._yearAxis.setLabelAutoRotation(float(rotation))
-
-    @Slot(bool)
-    def setAxisTitleVisibility(self, enabled):
-        self._temperatureAxis.setTitleVisible(enabled)
-        self._monthAxis.setTitleVisible(enabled)
-        self._yearAxis.setTitleVisible(enabled)
-
-    @Slot(bool)
-    def setAxisTitleFixed(self, enabled):
-        self._temperatureAxis.setTitleFixed(enabled)
-        self._monthAxis.setTitleFixed(enabled)
-        self._yearAxis.setTitleFixed(enabled)
-
-    @Slot()
-    def zoomToSelectedBar(self):
-        self._animationCameraX.stop()
-        self._animationCameraY.stop()
-        self._animationCameraZoom.stop()
-        self._animationCameraTarget.stop()
-
-        camera = self._graph.scene().activeCamera()
-        currentX = camera.xRotation()
-        currentY = camera.yRotation()
-        currentZoom = camera.zoomLevel()
-        currentTarget = camera.target()
-
-        self._animationCameraX.setStartValue(currentX)
-        self._animationCameraY.setStartValue(currentY)
-        self._animationCameraZoom.setStartValue(currentZoom)
-        self._animationCameraTarget.setStartValue(currentTarget)
-
-        selectedBar = (self._graph.selectedSeries().selectedBar()
-                       if self._graph.selectedSeries()
-                       else QBar3DSeries.invalidSelectionPosition())
-
-        if selectedBar != QBar3DSeries.invalidSelectionPosition():
-            # Normalize selected bar position within axis range to determine
-            # target coordinates
-            endTarget = QVector3D()
-            xMin = self._graph.columnAxis().min()
-            xRange = self._graph.columnAxis().max() - xMin
-            zMin = self._graph.rowAxis().min()
-            zRange = self._graph.rowAxis().max() - zMin
-            endTarget.setX((selectedBar.y() - xMin) / xRange * 2.0 - 1.0)
-            endTarget.setZ((selectedBar.x() - zMin) / zRange * 2.0 - 1.0)
-
-            # Rotate the camera so that it always points approximately to the
-            # graph center
-            endAngleX = 90.0 - degrees(atan(float(endTarget.z() / endTarget.x())))
-            if endTarget.x() > 0.0:
-                endAngleX -= 180.0
-            proxy = self._graph.selectedSeries().dataProxy()
-            barValue = proxy.itemAt(selectedBar.x(), selectedBar.y()).value()
-            endAngleY = 30.0 if barValue >= 0.0 else -30.0
-            if self._graph.valueAxis().reversed():
-                endAngleY *= -1.0
-
-            self._animationCameraX.setEndValue(float(endAngleX))
-            self._animationCameraY.setEndValue(endAngleY)
-            self._animationCameraZoom.setEndValue(250)
-            self._animationCameraTarget.setEndValue(endTarget)
-        else:
-            # No selected bar, so return to the default view
-            self._animationCameraX.setEndValue(self._defaultAngleX)
-            self._animationCameraY.setEndValue(self._defaultAngleY)
-            self._animationCameraZoom.setEndValue(self._defaultZoom)
-            self._animationCameraTarget.setEndValue(self._defaultTarget)
-
-        self._animationCameraX.start()
-        self._animationCameraY.start()
-        self._animationCameraZoom.start()
-        self._animationCameraTarget.start()
-
-    @Slot(bool)
-    def setDataModeToWeather(self, enabled):
-        if enabled:
-            self.changeDataMode(False)
-
-    @Slot(bool)
-    def setDataModeToCustom(self, enabled):
-        if enabled:
-            self.changeDataMode(True)
-
-    def changeShadowQuality(self, quality):
-        sq = QAbstract3DGraph.ShadowQuality(quality)
-        self._graph.setShadowQuality(sq)
-        self.shadowQualityChanged.emit(quality)
-
-    def rotateX(self, rotation):
-        self._xRotation = rotation
-        camera = self._graph.scene().activeCamera()
-        camera.setCameraPosition(self._xRotation, self._yRotation)
-
-    def rotateY(self, rotation):
-        self._yRotation = rotation
-        camera = self._graph.scene().activeCamera()
-        camera.setCameraPosition(self._xRotation, self._yRotation)
-
-    def setBackgroundEnabled(self, enabled):
-        self._graph.activeTheme().setBackgroundEnabled(bool(enabled))
-
-    def setGridEnabled(self, enabled):
-        self._graph.activeTheme().setGridEnabled(bool(enabled))
-
-    def setSmoothBars(self, smooth):
-        self._smooth = bool(smooth)
-        self._primarySeries.setMeshSmooth(self._smooth)
-        self._secondarySeries.setMeshSmooth(self._smooth)
-        self._customData.customSeries().setMeshSmooth(self._smooth)
-
-    def setSeriesVisibility(self, enabled):
-        self._secondarySeries.setVisible(bool(enabled))
-
-    def setReverseValueAxis(self, enabled):
-        self._graph.valueAxis().setReversed(enabled)
-
-    def setReflection(self, enabled):
-        self._graph.setReflection(enabled)
-
-    def changeDataMode(self, customData):
-        # Change between weather data and data from custom proxy
-        if customData:
-            self._graph.removeSeries(self._primarySeries)
-            self._graph.removeSeries(self._secondarySeries)
-            self._graph.addSeries(self._customData.customSeries())
-            self._graph.setValueAxis(self._customData.valueAxis())
-            self._graph.setRowAxis(self._customData.rowAxis())
-            self._graph.setColumnAxis(self._customData.colAxis())
-        else:
-            self._graph.removeSeries(self._customData.customSeries())
-            self._graph.addSeries(self._primarySeries)
-            self._graph.addSeries(self._secondarySeries)
-            self._graph.setValueAxis(self._temperatureAxis)
-            self._graph.setRowAxis(self._yearAxis)
-            self._graph.setColumnAxis(self._monthAxis)
diff --git a/examples/graphs/widgetgallery/highlightseries.py b/examples/graphs/widgetgallery/highlightseries.py
deleted file mode 100644 (file)
index 93ef3a7..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from PySide6.QtCore import QPoint, Qt, Slot
-from PySide6.QtGui import QLinearGradient, QVector3D
-from PySide6.QtGraphs import (QSurface3DSeries, QSurfaceDataItem, Q3DTheme)
-
-
-DARK_RED_POS = 1.0
-RED_POS = 0.8
-YELLOW_POS = 0.6
-GREEN_POS = 0.4
-DARK_GREEN_POS = 0.2
-
-
-class HighlightSeries(QSurface3DSeries):
-
-    def __init__(self):
-        super().__init__()
-        self._width = 100
-        self._height = 100
-        self._srcWidth = 0
-        self._srcHeight = 0
-        self._position = {}
-        self._topographicSeries = None
-        self._minHeight = 0.0
-        self.setDrawMode(QSurface3DSeries.DrawSurface)
-        self.setFlatShadingEnabled(True)
-        self.setVisible(False)
-
-    def setTopographicSeries(self, series):
-        self._topographicSeries = series
-        array = self._topographicSeries.dataProxy().array()
-        self._srcWidth = len(array[0])
-        self._srcHeight = len(array)
-        self._topographicSeries.selectedPointChanged.connect(self.handlePositionChange)
-
-    def setMinHeight(self, height):
-        self. m_minHeight = height
-
-    @Slot(QPoint)
-    def handlePositionChange(self, position):
-        self._position = position
-
-        if position == self.invalidSelectionPosition():
-            self.setVisible(False)
-            return
-
-        halfWidth = self._width / 2
-        halfHeight = self._height / 2
-
-        startX = position.y() - halfWidth
-        if startX < 0:
-            startX = 0
-        endX = position.y() + halfWidth
-        if endX > (self._srcWidth - 1):
-            endX = self._srcWidth - 1
-        startZ = position.x() - halfHeight
-        if startZ < 0:
-            startZ = 0
-        endZ = position.x() + halfHeight
-        if endZ > (self._srcHeight - 1):
-            endZ = self._srcHeight - 1
-
-        srcProxy = self._topographicSeries.dataProxy()
-        srcArray = srcProxy.array()
-
-        dataArray = []
-        for i in range(int(startZ), int(endZ)):
-            newRow = []
-            srcRow = srcArray[i]
-            for j in range(startX, endX):
-                pos = srcRow.at(j).position()
-                pos.setY(pos.y() + 0.1)
-                item = QSurfaceDataItem(QVector3D(pos))
-                newRow.append(item)
-            dataArray.append(newRow)
-        self.dataProxy().resetArray(dataArray)
-        self.setVisible(True)
-
-    @Slot(float)
-    def handleGradientChange(self, value):
-        ratio = self._minHeight / value
-
-        gr = QLinearGradient()
-        gr.setColorAt(0.0, Qt.black)
-        gr.setColorAt(DARK_GREEN_POS * ratio, Qt.darkGreen)
-        gr.setColorAt(GREEN_POS * ratio, Qt.green)
-        gr.setColorAt(YELLOW_POS * ratio, Qt.yellow)
-        gr.setColorAt(RED_POS * ratio, Qt.red)
-        gr.setColorAt(DARK_RED_POS * ratio, Qt.darkRed)
-
-        self.setBaseGradient(gr)
-        self.setColorStyle(Q3DTheme.ColorStyleRangeGradient)
diff --git a/examples/graphs/widgetgallery/main.py b/examples/graphs/widgetgallery/main.py
deleted file mode 100644 (file)
index 7bb2238..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-"""PySide6 port of the Qt Graphs widgetgallery example from Qt v6.x"""
-
-import sys
-
-from PySide6.QtCore import QSize
-from PySide6.QtWidgets import QApplication, QTabWidget
-
-from bargraph import BarGraph
-from scattergraph import ScatterGraph
-from surfacegraph import SurfaceGraph
-
-
-if __name__ == "__main__":
-    app = QApplication(sys.argv)
-
-    # Create a tab widget for creating own tabs for Q3DBars, Q3DScatter, and Q3DSurface
-    tabWidget = QTabWidget()
-    tabWidget.setWindowTitle("Widget Gallery")
-
-    screen_size = tabWidget.screen().size()
-    minimum_graph_size = QSize(screen_size.width() / 2, screen_size.height() / 1.75)
-
-    # Create bar graph
-    bars = BarGraph(minimum_graph_size, screen_size)
-    # Create scatter graph
-    scatter = ScatterGraph(minimum_graph_size, screen_size)
-    # Create surface graph
-    surface = SurfaceGraph(minimum_graph_size, screen_size)
-
-    # Add bars widget
-    tabWidget.addTab(bars.barsWidget(), "Bar Graph")
-    # Add scatter widget
-    tabWidget.addTab(scatter.scatterWidget(), "Scatter Graph")
-    # Add surface widget
-    tabWidget.addTab(surface.surfaceWidget(), "Surface Graph")
-
-    tabWidget.show()
-    sys.exit(app.exec())
diff --git a/examples/graphs/widgetgallery/rainfalldata.py b/examples/graphs/widgetgallery/rainfalldata.py
deleted file mode 100644 (file)
index d74f45a..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-import sys
-
-from pathlib import Path
-
-from PySide6.QtCore import QFile, QIODevice, QObject
-from PySide6.QtGraphs import (QBar3DSeries, QCategory3DAxis, QValue3DAxis)
-
-from variantbardataproxy import VariantBarDataProxy
-from variantbardatamapping import VariantBarDataMapping
-from variantdataset import VariantDataSet
-
-
-MONTHS = ["January", "February", "March", "April",
-          "May", "June", "July", "August", "September", "October",
-          "November", "December"]
-
-
-class RainfallData(QObject):
-
-    def __init__(self):
-        super().__init__()
-        self._columnCount = 0
-        self._rowCount = 0
-        self._years = []
-        self._numericMonths = []
-        self._proxy = VariantBarDataProxy()
-        self._mapping = None
-        self._dataSet = None
-        self._series = QBar3DSeries()
-        self._valueAxis = QValue3DAxis()
-        self._rowAxis = QCategory3DAxis()
-        self._colAxis = QCategory3DAxis()
-
-        # In data file the months are in numeric format, so create custom list
-        for i in range(1, 13):
-            self._numericMonths.append(str(i))
-
-        self._columnCount = len(self._numericMonths)
-
-        self.updateYearsList(2010, 2022)
-
-        # Create proxy and series
-        self._proxy = VariantBarDataProxy()
-        self._series = QBar3DSeries(self._proxy)
-
-        self._series.setItemLabelFormat("%.1f mm")
-
-        # Create the axes
-        self._rowAxis = QCategory3DAxis(self)
-        self._colAxis = QCategory3DAxis(self)
-        self._valueAxis = QValue3DAxis(self)
-        self._rowAxis.setAutoAdjustRange(True)
-        self._colAxis.setAutoAdjustRange(True)
-        self._valueAxis.setAutoAdjustRange(True)
-
-        # Set axis labels and titles
-        self._rowAxis.setTitle("Year")
-        self._colAxis.setTitle("Month")
-        self._valueAxis.setTitle("rainfall (mm)")
-        self._valueAxis.setSegmentCount(5)
-        self._rowAxis.setLabels(self._years)
-        self._colAxis.setLabels(MONTHS)
-        self._rowAxis.setTitleVisible(True)
-        self._colAxis.setTitleVisible(True)
-        self._valueAxis.setTitleVisible(True)
-
-        self.addDataSet()
-
-    def customSeries(self):
-        return self._series
-
-    def valueAxis(self):
-        return self._valueAxis
-
-    def rowAxis(self):
-        return self._rowAxis
-
-    def colAxis(self):
-        return self._colAxis
-
-    def updateYearsList(self, start, end):
-        self._years.clear()
-        for i in range(start, end + 1):
-            self._years.append(str(i))
-        self._rowCount = len(self._years)
-
-    def addDataSet(self):
-        # Create a new variant data set and data item list
-        self._dataSet = VariantDataSet()
-        itemList = []
-
-        # Read data from a data file into the data item list
-        file_path = Path(__file__).resolve().parent / "data" / "raindata.txt"
-        dataFile = QFile(file_path)
-        if dataFile.open(QIODevice.ReadOnly | QIODevice.Text):
-            data = dataFile.readAll().data().decode("utf8")
-            for line in data.split("\n"):
-                if line and not line.startswith("#"):  # Ignore comments
-                    tokens = line.split(",")
-                    # Each line has three data items: Year, month, and
-                    # rainfall value
-                    if len(tokens) >= 3:
-                        # Store year and month as strings, and rainfall value
-                        # as double into a variant data item and add the item to
-                        # the item list.
-                        newItem = []
-                        newItem.append(tokens[0].strip())
-                        newItem.append(tokens[1].strip())
-                        newItem.append(float(tokens[2].strip()))
-                        itemList.append(newItem)
-        else:
-            print("Unable to open data file:", dataFile.fileName(),
-                  file=sys.stderr)
-
-        # Add items to the data set and set it to the proxy
-        self._dataSet.addItems(itemList)
-        self._proxy.setDataSet(self._dataSet)
-
-        # Create new mapping for the data and set it to the proxy
-        self._mapping = VariantBarDataMapping(0, 1, 2,
-                                              self._years, self._numericMonths)
-        self._proxy.setMapping(self._mapping)
diff --git a/examples/graphs/widgetgallery/scatterdatamodifier.py b/examples/graphs/widgetgallery/scatterdatamodifier.py
deleted file mode 100644 (file)
index a9ca382..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from math import cos, degrees, sqrt
-
-from PySide6.QtCore import QObject, Signal, Slot, Qt
-from PySide6.QtGui import QVector3D
-from PySide6.QtGraphs import (QAbstract3DGraph, QAbstract3DSeries,
-                              QScatterDataItem, QScatterDataProxy,
-                              QScatter3DSeries, Q3DCamera, Q3DTheme)
-
-from axesinputhandler import AxesInputHandler
-
-
-NUMBER_OF_ITEMS = 10000
-CURVE_DIVIDER = 7.5
-LOWER_NUMBER_OF_ITEMS = 900
-LOWER_CURVE_DIVIDER = 0.75
-
-
-class ScatterDataModifier(QObject):
-
-    backgroundEnabledChanged = Signal(bool)
-    gridEnabledChanged = Signal(bool)
-    shadowQualityChanged = Signal(int)
-
-    def __init__(self, scatter, parent):
-        super().__init__(parent)
-
-        self._graph = scatter
-
-        self._style = QAbstract3DSeries.MeshSphere
-        self._smooth = True
-        self._inputHandler = AxesInputHandler(scatter)
-        self._autoAdjust = True
-        self._itemCount = LOWER_NUMBER_OF_ITEMS
-        self._CURVE_DIVIDER = LOWER_CURVE_DIVIDER
-        self._inputHandler = AxesInputHandler(scatter)
-
-        self._graph.activeTheme().setType(Q3DTheme.ThemeStoneMoss)
-        self._graph.setShadowQuality(QAbstract3DGraph.ShadowQualitySoftHigh)
-        self._graph.scene().activeCamera().setCameraPreset(Q3DCamera.CameraPresetFront)
-        self._graph.scene().activeCamera().setZoomLevel(80.0)
-
-        self._proxy = QScatterDataProxy()
-        self._series = QScatter3DSeries(self._proxy)
-        self._series.setItemLabelFormat("@xTitle: @xLabel @yTitle: @yLabel @zTitle: @zLabel")
-        self._series.setMeshSmooth(self._smooth)
-        self._graph.addSeries(self._series)
-
-        # Give ownership of the handler to the graph and make it the active
-        # handler
-        self._graph.setActiveInputHandler(self._inputHandler)
-
-        # Give our axes to the input handler
-        self._inputHandler.setAxes(self._graph.axisX(), self._graph.axisZ(),
-                                   self._graph.axisY())
-
-        self.addData()
-
-    def addData(self):
-        # Configure the axes according to the data
-        self._graph.axisX().setTitle("X")
-        self._graph.axisY().setTitle("Y")
-        self._graph.axisZ().setTitle("Z")
-
-        dataArray = []
-        limit = int(sqrt(self._itemCount) / 2.0)
-        for i in range(-limit, limit):
-            for j in range(-limit, limit):
-                x = float(i) + 0.5
-                y = cos(degrees(float(i * j) / self._CURVE_DIVIDER))
-                z = float(j) + 0.5
-                dataArray.append(QScatterDataItem(QVector3D(x, y, z)))
-
-        self._graph.seriesList()[0].dataProxy().resetArray(dataArray)
-
-    @Slot(int)
-    def changeStyle(self, style):
-        comboBox = self.sender()
-        if comboBox:
-            self._style = comboBox.itemData(style)
-            if self._graph.seriesList():
-                self._graph.seriesList()[0].setMesh(self._style)
-
-    @Slot(int)
-    def setSmoothDots(self, smooth):
-        self._smooth = smooth == Qt.Checked.value
-        series = self._graph.seriesList()[0]
-        series.setMeshSmooth(self._smooth)
-
-    @Slot(int)
-    def changeTheme(self, theme):
-        currentTheme = self._graph.activeTheme()
-        currentTheme.setType(Q3DTheme.Theme(theme))
-        self.backgroundEnabledChanged.emit(currentTheme.isBackgroundEnabled())
-        self.gridEnabledChanged.emit(currentTheme.isGridEnabled())
-
-    @Slot()
-    def changePresetCamera(self):
-        preset = Q3DCamera.CameraPresetFrontLow.value
-
-        camera = self._graph.scene().activeCamera()
-        camera.setCameraPreset(Q3DCamera.CameraPreset(preset))
-
-        preset += 1
-        if preset > Q3DCamera.CameraPresetDirectlyBelow.value:
-            preset = Q3DCamera.CameraPresetFrontLow.value
-
-    @Slot(QAbstract3DGraph.ShadowQuality)
-    def shadowQualityUpdatedByVisual(self, sq):
-        self.shadowQualityChanged.emit(sq.value)
-
-    @Slot(int)
-    def changeShadowQuality(self, quality):
-        sq = QAbstract3DGraph.ShadowQuality(quality)
-        self._graph.setShadowQuality(sq)
-
-    @Slot(int)
-    def setBackgroundEnabled(self, enabled):
-        self._graph.activeTheme().setBackgroundEnabled(enabled == Qt.Checked.value)
-
-    @Slot(int)
-    def setGridEnabled(self, enabled):
-        self._graph.activeTheme().setGridEnabled(enabled == Qt.Checked.value)
-
-    @Slot()
-    def toggleItemCount(self):
-        if self._itemCount == NUMBER_OF_ITEMS:
-            self._itemCount = LOWER_NUMBER_OF_ITEMS
-            self._CURVE_DIVIDER = LOWER_CURVE_DIVIDER
-        else:
-            self._itemCount = NUMBER_OF_ITEMS
-            self._CURVE_DIVIDER = CURVE_DIVIDER
-
-        self._graph.seriesList()[0].dataProxy().resetArray([])
-        self.addData()
-
-    @Slot()
-    def toggleRanges(self):
-        if not self._autoAdjust:
-            self._graph.axisX().setAutoAdjustRange(True)
-            self._graph.axisZ().setAutoAdjustRange(True)
-            self._inputHandler.setDragSpeedModifier(1.5)
-            self._autoAdjust = True
-        else:
-            self._graph.axisX().setRange(-10.0, 10.0)
-            self._graph.axisZ().setRange(-10.0, 10.0)
-            self._inputHandler.setDragSpeedModifier(15.0)
-            self._autoAdjust = False
diff --git a/examples/graphs/widgetgallery/scattergraph.py b/examples/graphs/widgetgallery/scattergraph.py
deleted file mode 100644 (file)
index 236348e..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from PySide6.QtCore import QObject, QSize, Qt
-from PySide6.QtWidgets import (QCheckBox, QComboBox, QCommandLinkButton,
-                               QLabel, QHBoxLayout, QSizePolicy,
-                               QVBoxLayout, QWidget, )
-from PySide6.QtQuickWidgets import QQuickWidget
-from PySide6.QtGraphs import (QAbstract3DSeries, Q3DScatter)
-
-from scatterdatamodifier import ScatterDataModifier
-
-
-class ScatterGraph(QObject):
-
-    def __init__(self, minimum_graph_size, maximum_graph_size):
-        super().__init__()
-        self._scatterGraph = Q3DScatter()
-        self._scatterWidget = QWidget()
-        hLayout = QHBoxLayout(self._scatterWidget)
-        self._scatterGraph.setMinimumSize(minimum_graph_size)
-        self._scatterGraph.setMaximumSize(maximum_graph_size)
-        self._scatterGraph.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
-        self._scatterGraph.setFocusPolicy(Qt.StrongFocus)
-        self._scatterGraph.setResizeMode(QQuickWidget.SizeRootObjectToView)
-        hLayout.addWidget(self._scatterGraph, 1)
-
-        vLayout = QVBoxLayout()
-        hLayout.addLayout(vLayout)
-
-        cameraButton = QCommandLinkButton(self._scatterWidget)
-        cameraButton.setText("Change camera preset")
-        cameraButton.setDescription("Switch between a number of preset camera positions")
-        cameraButton.setIconSize(QSize(0, 0))
-
-        itemCountButton = QCommandLinkButton(self._scatterWidget)
-        itemCountButton.setText("Toggle item count")
-        itemCountButton.setDescription("Switch between 900 and 10000 data points")
-        itemCountButton.setIconSize(QSize(0, 0))
-
-        rangeButton = QCommandLinkButton(self._scatterWidget)
-        rangeButton.setText("Toggle axis ranges")
-        rangeButton.setDescription("Switch between automatic axis ranges and preset ranges")
-        rangeButton.setIconSize(QSize(0, 0))
-
-        backgroundCheckBox = QCheckBox(self._scatterWidget)
-        backgroundCheckBox.setText("Show background")
-        backgroundCheckBox.setChecked(True)
-
-        gridCheckBox = QCheckBox(self._scatterWidget)
-        gridCheckBox.setText("Show grid")
-        gridCheckBox.setChecked(True)
-
-        smoothCheckBox = QCheckBox(self._scatterWidget)
-        smoothCheckBox.setText("Smooth dots")
-        smoothCheckBox.setChecked(True)
-
-        itemStyleList = QComboBox(self._scatterWidget)
-        itemStyleList.addItem("Sphere", QAbstract3DSeries.MeshSphere)
-        itemStyleList.addItem("Cube", QAbstract3DSeries.MeshCube)
-        itemStyleList.addItem("Minimal", QAbstract3DSeries.MeshMinimal)
-        itemStyleList.addItem("Point", QAbstract3DSeries.MeshPoint)
-        itemStyleList.setCurrentIndex(0)
-
-        themeList = QComboBox(self._scatterWidget)
-        themeList.addItem("Qt")
-        themeList.addItem("Primary Colors")
-        themeList.addItem("Digia")
-        themeList.addItem("Stone Moss")
-        themeList.addItem("Army Blue")
-        themeList.addItem("Retro")
-        themeList.addItem("Ebony")
-        themeList.addItem("Isabelle")
-        themeList.setCurrentIndex(3)
-
-        shadowQuality = QComboBox(self._scatterWidget)
-        shadowQuality.addItem("None")
-        shadowQuality.addItem("Low")
-        shadowQuality.addItem("Medium")
-        shadowQuality.addItem("High")
-        shadowQuality.addItem("Low Soft")
-        shadowQuality.addItem("Medium Soft")
-        shadowQuality.addItem("High Soft")
-        shadowQuality.setCurrentIndex(6)
-
-        vLayout.addWidget(cameraButton)
-        vLayout.addWidget(itemCountButton)
-        vLayout.addWidget(rangeButton)
-        vLayout.addWidget(backgroundCheckBox)
-        vLayout.addWidget(gridCheckBox)
-        vLayout.addWidget(smoothCheckBox)
-        vLayout.addWidget(QLabel("Change dot style"))
-        vLayout.addWidget(itemStyleList)
-        vLayout.addWidget(QLabel("Change theme"))
-        vLayout.addWidget(themeList)
-        vLayout.addWidget(QLabel("Adjust shadow quality"))
-        vLayout.addWidget(shadowQuality, 1, Qt.AlignTop)
-
-        self._modifier = ScatterDataModifier(self._scatterGraph, self)
-
-        cameraButton.clicked.connect(self._modifier.changePresetCamera)
-        itemCountButton.clicked.connect(self._modifier.toggleItemCount)
-        rangeButton.clicked.connect(self._modifier.toggleRanges)
-
-        backgroundCheckBox.stateChanged.connect(self._modifier.setBackgroundEnabled)
-        gridCheckBox.stateChanged.connect(self._modifier.setGridEnabled)
-        smoothCheckBox.stateChanged.connect(self._modifier.setSmoothDots)
-
-        self._modifier.backgroundEnabledChanged.connect(backgroundCheckBox.setChecked)
-        self._modifier.gridEnabledChanged.connect(gridCheckBox.setChecked)
-        itemStyleList.currentIndexChanged.connect(self._modifier.changeStyle)
-
-        themeList.currentIndexChanged.connect(self._modifier.changeTheme)
-
-        shadowQuality.currentIndexChanged.connect(self._modifier.changeShadowQuality)
-
-        self._modifier.shadowQualityChanged.connect(shadowQuality.setCurrentIndex)
-        self._scatterGraph.shadowQualityChanged.connect(self._modifier.shadowQualityUpdatedByVisual)
-
-    def scatterWidget(self):
-        return self._scatterWidget
diff --git a/examples/graphs/widgetgallery/surfacegraph.py b/examples/graphs/widgetgallery/surfacegraph.py
deleted file mode 100644 (file)
index 4052da8..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from surfacegraphmodifier import SurfaceGraphModifier
-
-from PySide6.QtCore import QObject, Qt
-from PySide6.QtGui import QBrush, QIcon, QLinearGradient, QPainter, QPixmap
-from PySide6.QtWidgets import (QGroupBox, QCheckBox, QLabel, QHBoxLayout,
-                               QPushButton, QRadioButton, QSizePolicy, QSlider,
-                               QVBoxLayout, QWidget)
-from PySide6.QtQuickWidgets import QQuickWidget
-from PySide6.QtGraphs import Q3DSurface
-
-
-def gradientBtoYPB_Pixmap():
-    grBtoY = QLinearGradient(0, 0, 1, 100)
-    grBtoY.setColorAt(1.0, Qt.black)
-    grBtoY.setColorAt(0.67, Qt.blue)
-    grBtoY.setColorAt(0.33, Qt.red)
-    grBtoY.setColorAt(0.0, Qt.yellow)
-    pm = QPixmap(24, 100)
-    with QPainter(pm) as pmp:
-        pmp.setBrush(QBrush(grBtoY))
-        pmp.setPen(Qt.NoPen)
-        pmp.drawRect(0, 0, 24, 100)
-    return pm
-
-
-def gradientGtoRPB_Pixmap():
-    grGtoR = QLinearGradient(0, 0, 1, 100)
-    grGtoR.setColorAt(1.0, Qt.darkGreen)
-    grGtoR.setColorAt(0.5, Qt.yellow)
-    grGtoR.setColorAt(0.2, Qt.red)
-    grGtoR.setColorAt(0.0, Qt.darkRed)
-    pm = QPixmap(24, 100)
-    with QPainter(pm) as pmp:
-        pmp.setBrush(QBrush(grGtoR))
-        pmp.setPen(Qt.NoPen)
-        pmp.drawRect(0, 0, 24, 100)
-    return pm
-
-
-def highlightPixmap():
-    HEIGHT = 400
-    WIDTH = 110
-    BORDER = 10
-    gr = QLinearGradient(0, 0, 1, HEIGHT - 2 * BORDER)
-    gr.setColorAt(1.0, Qt.black)
-    gr.setColorAt(0.8, Qt.darkGreen)
-    gr.setColorAt(0.6, Qt.green)
-    gr.setColorAt(0.4, Qt.yellow)
-    gr.setColorAt(0.2, Qt.red)
-    gr.setColorAt(0.0, Qt.darkRed)
-    pmHighlight = QPixmap(WIDTH, HEIGHT)
-    pmHighlight.fill(Qt.transparent)
-    with QPainter(pmHighlight) as pmpHighlight:
-        pmpHighlight.setBrush(QBrush(gr))
-        pmpHighlight.setPen(Qt.NoPen)
-        pmpHighlight.drawRect(BORDER, BORDER, 35, HEIGHT - 2 * BORDER)
-        pmpHighlight.setPen(Qt.black)
-        step = (HEIGHT - 2 * BORDER) / 5
-        for i in range(0, 6):
-            yPos = i * step + BORDER
-            pmpHighlight.drawLine(BORDER, yPos, 55, yPos)
-            HEIGHT = 550 - (i * 110)
-            pmpHighlight.drawText(60, yPos + 2, f"{HEIGHT} m")
-    return pmHighlight
-
-
-class SurfaceGraph(QObject):
-
-    def __init__(self, minimum_graph_size, maximum_graph_size):
-        super().__init__()
-        self._surfaceGraph = Q3DSurface()
-        self._surfaceWidget = QWidget()
-        hLayout = QHBoxLayout(self._surfaceWidget)
-        self._surfaceGraph.setMinimumSize(minimum_graph_size)
-        self._surfaceGraph.setMaximumSize(maximum_graph_size)
-        self._surfaceGraph.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
-        self._surfaceGraph.setFocusPolicy(Qt.StrongFocus)
-        self._surfaceGraph.setResizeMode(QQuickWidget.SizeRootObjectToView)
-        hLayout.addWidget(self._surfaceGraph, 1)
-        vLayout = QVBoxLayout()
-        hLayout.addLayout(vLayout)
-        vLayout.setAlignment(Qt.AlignTop)
-        # Create control widgets
-        modelGroupBox = QGroupBox("Model")
-        sqrtSinModelRB = QRadioButton(self._surfaceWidget)
-        sqrtSinModelRB.setText("Sqrt and Sin")
-        sqrtSinModelRB.setChecked(False)
-        heightMapModelRB = QRadioButton(self._surfaceWidget)
-        heightMapModelRB.setText("Multiseries\nHeight Map")
-        heightMapModelRB.setChecked(False)
-        texturedModelRB = QRadioButton(self._surfaceWidget)
-        texturedModelRB.setText("Textured\nTopography")
-        texturedModelRB.setChecked(False)
-        modelVBox = QVBoxLayout()
-        modelVBox.addWidget(sqrtSinModelRB)
-        modelVBox.addWidget(heightMapModelRB)
-        modelVBox.addWidget(texturedModelRB)
-        modelGroupBox.setLayout(modelVBox)
-        selectionGroupBox = QGroupBox("Graph Selection Mode")
-        modeNoneRB = QRadioButton(self._surfaceWidget)
-        modeNoneRB.setText("No selection")
-        modeNoneRB.setChecked(False)
-        modeItemRB = QRadioButton(self._surfaceWidget)
-        modeItemRB.setText("Item")
-        modeItemRB.setChecked(False)
-        modeSliceRowRB = QRadioButton(self._surfaceWidget)
-        modeSliceRowRB.setText("Row Slice")
-        modeSliceRowRB.setChecked(False)
-        modeSliceColumnRB = QRadioButton(self._surfaceWidget)
-        modeSliceColumnRB.setText("Column Slice")
-        modeSliceColumnRB.setChecked(False)
-        selectionVBox = QVBoxLayout()
-        selectionVBox.addWidget(modeNoneRB)
-        selectionVBox.addWidget(modeItemRB)
-        selectionVBox.addWidget(modeSliceRowRB)
-        selectionVBox.addWidget(modeSliceColumnRB)
-        selectionGroupBox.setLayout(selectionVBox)
-        axisGroupBox = QGroupBox("Axis ranges")
-        axisMinSliderX = QSlider(Qt.Horizontal)
-        axisMinSliderX.setMinimum(0)
-        axisMinSliderX.setTickInterval(1)
-        axisMinSliderX.setEnabled(True)
-        axisMaxSliderX = QSlider(Qt.Horizontal)
-        axisMaxSliderX.setMinimum(1)
-        axisMaxSliderX.setTickInterval(1)
-        axisMaxSliderX.setEnabled(True)
-        axisMinSliderZ = QSlider(Qt.Horizontal)
-        axisMinSliderZ.setMinimum(0)
-        axisMinSliderZ.setTickInterval(1)
-        axisMinSliderZ.setEnabled(True)
-        axisMaxSliderZ = QSlider(Qt.Horizontal)
-        axisMaxSliderZ.setMinimum(1)
-        axisMaxSliderZ.setTickInterval(1)
-        axisMaxSliderZ.setEnabled(True)
-        axisVBox = QVBoxLayout(axisGroupBox)
-        axisVBox.addWidget(QLabel("Column range"))
-        axisVBox.addWidget(axisMinSliderX)
-        axisVBox.addWidget(axisMaxSliderX)
-        axisVBox.addWidget(QLabel("Row range"))
-        axisVBox.addWidget(axisMinSliderZ)
-        axisVBox.addWidget(axisMaxSliderZ)
-        # Mode-dependent controls
-        # sqrt-sin
-        colorGroupBox = QGroupBox("Custom gradient")
-
-        pixmap = gradientBtoYPB_Pixmap()
-        gradientBtoYPB = QPushButton(self._surfaceWidget)
-        gradientBtoYPB.setIcon(QIcon(pixmap))
-        gradientBtoYPB.setIconSize(pixmap.size())
-
-        pixmap = gradientGtoRPB_Pixmap()
-        gradientGtoRPB = QPushButton(self._surfaceWidget)
-        gradientGtoRPB.setIcon(QIcon(pixmap))
-        gradientGtoRPB.setIconSize(pixmap.size())
-
-        colorHBox = QHBoxLayout(colorGroupBox)
-        colorHBox.addWidget(gradientBtoYPB)
-        colorHBox.addWidget(gradientGtoRPB)
-        # Multiseries heightmap
-        showGroupBox = QGroupBox("Show Object")
-        showGroupBox.setVisible(False)
-        checkboxShowOilRigOne = QCheckBox("Oil Rig 1")
-        checkboxShowOilRigOne.setChecked(True)
-        checkboxShowOilRigTwo = QCheckBox("Oil Rig 2")
-        checkboxShowOilRigTwo.setChecked(True)
-        checkboxShowRefinery = QCheckBox("Refinery")
-        showVBox = QVBoxLayout()
-        showVBox.addWidget(checkboxShowOilRigOne)
-        showVBox.addWidget(checkboxShowOilRigTwo)
-        showVBox.addWidget(checkboxShowRefinery)
-        showGroupBox.setLayout(showVBox)
-        visualsGroupBox = QGroupBox("Visuals")
-        visualsGroupBox.setVisible(False)
-        checkboxVisualsSeeThrough = QCheckBox("See-Through")
-        checkboxHighlightOil = QCheckBox("Highlight Oil")
-        checkboxShowShadows = QCheckBox("Shadows")
-        checkboxShowShadows.setChecked(True)
-        visualVBox = QVBoxLayout(visualsGroupBox)
-        visualVBox.addWidget(checkboxVisualsSeeThrough)
-        visualVBox.addWidget(checkboxHighlightOil)
-        visualVBox.addWidget(checkboxShowShadows)
-        labelSelection = QLabel("Selection:")
-        labelSelection.setVisible(False)
-        labelSelectedItem = QLabel("Nothing")
-        labelSelectedItem.setVisible(False)
-        # Textured topography heightmap
-        enableTexture = QCheckBox("Surface texture")
-        enableTexture.setVisible(False)
-
-        label = QLabel(self._surfaceWidget)
-        label.setPixmap(highlightPixmap())
-        heightMapGroupBox = QGroupBox("Highlight color map")
-        colorMapVBox = QVBoxLayout()
-        colorMapVBox.addWidget(label)
-        heightMapGroupBox.setLayout(colorMapVBox)
-        heightMapGroupBox.setVisible(False)
-        # Populate vertical layout
-        # Common
-        vLayout.addWidget(modelGroupBox)
-        vLayout.addWidget(selectionGroupBox)
-        vLayout.addWidget(axisGroupBox)
-        # Sqrt Sin
-        vLayout.addWidget(colorGroupBox)
-        # Multiseries heightmap
-        vLayout.addWidget(showGroupBox)
-        vLayout.addWidget(visualsGroupBox)
-        vLayout.addWidget(labelSelection)
-        vLayout.addWidget(labelSelectedItem)
-        # Textured topography
-        vLayout.addWidget(heightMapGroupBox)
-        vLayout.addWidget(enableTexture)
-        # Create the controller
-        modifier = SurfaceGraphModifier(self._surfaceGraph, labelSelectedItem, self)
-        # Connect widget controls to controller
-        heightMapModelRB.toggled.connect(modifier.enableHeightMapModel)
-        sqrtSinModelRB.toggled.connect(modifier.enableSqrtSinModel)
-        texturedModelRB.toggled.connect(modifier.enableTopographyModel)
-        modeNoneRB.toggled.connect(modifier.toggleModeNone)
-        modeItemRB.toggled.connect(modifier.toggleModeItem)
-        modeSliceRowRB.toggled.connect(modifier.toggleModeSliceRow)
-        modeSliceColumnRB.toggled.connect(modifier.toggleModeSliceColumn)
-        axisMinSliderX.valueChanged.connect(modifier.adjustXMin)
-        axisMaxSliderX.valueChanged.connect(modifier.adjustXMax)
-        axisMinSliderZ.valueChanged.connect(modifier.adjustZMin)
-        axisMaxSliderZ.valueChanged.connect(modifier.adjustZMax)
-        # Mode dependent connections
-        gradientBtoYPB.pressed.connect(modifier.setBlackToYellowGradient)
-        gradientGtoRPB.pressed.connect(modifier.setGreenToRedGradient)
-        checkboxShowOilRigOne.stateChanged.connect(modifier.toggleItemOne)
-        checkboxShowOilRigTwo.stateChanged.connect(modifier.toggleItemTwo)
-        checkboxShowRefinery.stateChanged.connect(modifier.toggleItemThree)
-        checkboxVisualsSeeThrough.stateChanged.connect(modifier.toggleSeeThrough)
-        checkboxHighlightOil.stateChanged.connect(modifier.toggleOilHighlight)
-        checkboxShowShadows.stateChanged.connect(modifier.toggleShadows)
-        enableTexture.stateChanged.connect(modifier.toggleSurfaceTexture)
-        # Connections to disable features depending on mode
-        sqrtSinModelRB.toggled.connect(colorGroupBox.setVisible)
-        heightMapModelRB.toggled.connect(showGroupBox.setVisible)
-        heightMapModelRB.toggled.connect(visualsGroupBox.setVisible)
-        heightMapModelRB.toggled.connect(labelSelection.setVisible)
-        heightMapModelRB.toggled.connect(labelSelectedItem.setVisible)
-        texturedModelRB.toggled.connect(enableTexture.setVisible)
-        texturedModelRB.toggled.connect(heightMapGroupBox.setVisible)
-        modifier.setAxisMinSliderX(axisMinSliderX)
-        modifier.setAxisMaxSliderX(axisMaxSliderX)
-        modifier.setAxisMinSliderZ(axisMinSliderZ)
-        modifier.setAxisMaxSliderZ(axisMaxSliderZ)
-        sqrtSinModelRB.setChecked(True)
-        modeItemRB.setChecked(True)
-        enableTexture.setChecked(True)
-
-    def surfaceWidget(self):
-        return self._surfaceWidget
diff --git a/examples/graphs/widgetgallery/surfacegraphmodifier.py b/examples/graphs/widgetgallery/surfacegraphmodifier.py
deleted file mode 100644 (file)
index cb0ec4a..0000000
+++ /dev/null
@@ -1,642 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-import os
-from math import sqrt, sin
-from pathlib import Path
-
-from PySide6.QtCore import QObject, QPropertyAnimation, Qt, Slot
-from PySide6.QtGui import (QColor, QFont, QImage, QLinearGradient,
-                           QQuaternion, QVector3D)
-from PySide6.QtGraphs import (QAbstract3DGraph, QCustom3DItem,
-                              QCustom3DLabel, QHeightMapSurfaceDataProxy,
-                              QValue3DAxis, QSurfaceDataItem,
-                              QSurfaceDataProxy, QSurface3DSeries,
-                              Q3DInputHandler, Q3DCamera, Q3DTheme)
-
-
-from highlightseries import HighlightSeries
-from topographicseries import TopographicSeries
-from custominputhandler import CustomInputHandler
-
-
-SAMPLE_COUNT_X = 150
-SAMPLE_COUNT_Z = 150
-HEIGHTMAP_GRID_STEP_X = 6
-HEIGHTMAP_GRID_STEP_Z = 6
-SAMPLE_MIN = -8.0
-SAMPLE_MAX = 8.0
-
-AREA_WIDTH = 8000.0
-AREA_HEIGHT = 8000.0
-ASPECT_RATIO = 0.1389
-MIN_RANGE = AREA_WIDTH * 0.49
-
-
-class SurfaceGraphModifier(QObject):
-
-    def __init__(self, surface, label, parent):
-        super().__init__(parent)
-        self._data_path = Path(__file__).resolve().parent / "data"
-        self._graph = surface
-        self._textField = label
-        self._sqrtSinProxy = None
-        self._sqrtSinSeries = None
-        self._heightMapProxyOne = None
-        self._heightMapProxyTwo = None
-        self._heightMapProxyThree = None
-        self._heightMapSeriesOne = None
-        self._heightMapSeriesTwo = None
-        self._heightMapSeriesThree = None
-
-        self._axisMinSliderX = None
-        self._axisMaxSliderX = None
-        self._axisMinSliderZ = None
-        self._axisMaxSliderZ = None
-        self._rangeMinX = 0.0
-        self._rangeMinZ = 0.0
-        self._stepX = 0.0
-        self._stepZ = 0.0
-        self._heightMapWidth = 0
-        self._heightMapHeight = 0
-
-        self._selectionAnimation = None
-        self._titleLabel = None
-        self._previouslyAnimatedItem = None
-        self._previousScaling = {}
-
-        self._topography = None
-        self._highlight = None
-        self._highlightWidth = 0
-        self._highlightHeight = 0
-
-        self._customInputHandler = None
-        self._defaultInputHandler = Q3DInputHandler()
-
-        ac = self._graph.scene().activeCamera()
-        ac.setZoomLevel(85.0)
-        ac.setCameraPreset(Q3DCamera.CameraPresetIsometricRight)
-        self._graph.activeTheme().setType(Q3DTheme.ThemeRetro)
-
-        self._x_axis = QValue3DAxis()
-        self._y_axis = QValue3DAxis()
-        self._z_axis = QValue3DAxis()
-        self._graph.setAxisX(self._x_axis)
-        self._graph.setAxisY(self._y_axis)
-        self._graph.setAxisZ(self._z_axis)
-
-        #
-        # Sqrt Sin
-        #
-        self._sqrtSinProxy = QSurfaceDataProxy()
-        self._sqrtSinSeries = QSurface3DSeries(self._sqrtSinProxy)
-        self.fillSqrtSinProxy()
-
-        #
-        # Multisurface heightmap
-        #
-        # Create the first surface layer
-        heightMapImageOne = QImage(self._data_path / "layer_1.png")
-        self._heightMapProxyOne = QHeightMapSurfaceDataProxy(heightMapImageOne)
-        self._heightMapSeriesOne = QSurface3DSeries(self._heightMapProxyOne)
-        self._heightMapSeriesOne.setItemLabelFormat("(@xLabel, @zLabel): @yLabel")
-        self._heightMapProxyOne.setValueRanges(34.0, 40.0, 18.0, 24.0)
-
-        # Create the other 2 surface layers
-        heightMapImageTwo = QImage(self._data_path / "layer_2.png")
-        self._heightMapProxyTwo = QHeightMapSurfaceDataProxy(heightMapImageTwo)
-        self._heightMapSeriesTwo = QSurface3DSeries(self._heightMapProxyTwo)
-        self._heightMapSeriesTwo.setItemLabelFormat("(@xLabel, @zLabel): @yLabel")
-        self._heightMapProxyTwo.setValueRanges(34.0, 40.0, 18.0, 24.0)
-
-        heightMapImageThree = QImage(self._data_path / "layer_3.png")
-        self._heightMapProxyThree = QHeightMapSurfaceDataProxy(heightMapImageThree)
-        self._heightMapSeriesThree = QSurface3DSeries(self._heightMapProxyThree)
-        self._heightMapSeriesThree.setItemLabelFormat("(@xLabel, @zLabel): @yLabel")
-        self._heightMapProxyThree.setValueRanges(34.0, 40.0, 18.0, 24.0)
-
-        # The images are the same size, so it's enough to get the dimensions
-        # from one
-        self._heightMapWidth = heightMapImageOne.width()
-        self._heightMapHeight = heightMapImageOne.height()
-
-        # Set the gradients for multi-surface layers
-        grOne = QLinearGradient()
-        grOne.setColorAt(0.0, Qt.black)
-        grOne.setColorAt(0.38, Qt.darkYellow)
-        grOne.setColorAt(0.39, Qt.darkGreen)
-        grOne.setColorAt(0.5, Qt.darkGray)
-        grOne.setColorAt(1.0, Qt.gray)
-        self._heightMapSeriesOne.setBaseGradient(grOne)
-        self._heightMapSeriesOne.setColorStyle(Q3DTheme.ColorStyleRangeGradient)
-
-        grTwo = QLinearGradient()
-        grTwo.setColorAt(0.39, Qt.blue)
-        grTwo.setColorAt(0.4, Qt.white)
-        self._heightMapSeriesTwo.setBaseGradient(grTwo)
-        self._heightMapSeriesTwo.setColorStyle(Q3DTheme.ColorStyleRangeGradient)
-
-        grThree = QLinearGradient()
-        grThree.setColorAt(0.0, Qt.white)
-        grThree.setColorAt(0.05, Qt.black)
-        self._heightMapSeriesThree.setBaseGradient(grThree)
-        self._heightMapSeriesThree.setColorStyle(Q3DTheme.ColorStyleRangeGradient)
-
-        # Custom items and label
-        self._graph.selectedElementChanged.connect(self.handleElementSelected)
-
-        self._selectionAnimation = QPropertyAnimation(self)
-        self._selectionAnimation.setPropertyName(b"scaling")
-        self._selectionAnimation.setDuration(500)
-        self._selectionAnimation.setLoopCount(-1)
-
-        titleFont = QFont("Century Gothic", 30)
-        titleFont.setBold(True)
-        self._titleLabel = QCustom3DLabel("Oil Rigs on Imaginary Sea", titleFont,
-                                          QVector3D(0.0, 1.2, 0.0),
-                                          QVector3D(1.0, 1.0, 0.0),
-                                          QQuaternion())
-        self._titleLabel.setPositionAbsolute(True)
-        self._titleLabel.setFacingCamera(True)
-        self._titleLabel.setBackgroundColor(QColor(0x66cdaa))
-        self._graph.addCustomItem(self._titleLabel)
-        self._titleLabel.setVisible(False)
-
-        # Make two of the custom object visible
-        self.toggleItemOne(True)
-        self.toggleItemTwo(True)
-
-        #
-        # Topographic map
-        #
-        self._topography = TopographicSeries()
-        file_name = os.fspath(self._data_path / "topography.png")
-        self._topography.setTopographyFile(file_name, AREA_WIDTH, AREA_HEIGHT)
-        self._topography.setItemLabelFormat("@yLabel m")
-
-        self._highlight = HighlightSeries()
-        self._highlight.setTopographicSeries(self._topography)
-        self._highlight.setMinHeight(MIN_RANGE * ASPECT_RATIO)
-        self._highlight.handleGradientChange(AREA_WIDTH * ASPECT_RATIO)
-        self._graph.axisY().maxChanged.connect(self._highlight.handleGradientChange)
-
-        self._customInputHandler = CustomInputHandler(self._graph)
-        self._customInputHandler.setHighlightSeries(self._highlight)
-        self._customInputHandler.setAxes(self._x_axis, self._y_axis, self._z_axis)
-        self._customInputHandler.setLimits(0.0, AREA_WIDTH, MIN_RANGE)
-        self._customInputHandler.setAspectRatio(ASPECT_RATIO)
-
-    def fillSqrtSinProxy(self):
-        stepX = (SAMPLE_MAX - SAMPLE_MIN) / float(SAMPLE_COUNT_X - 1)
-        stepZ = (SAMPLE_MAX - SAMPLE_MIN) / float(SAMPLE_COUNT_Z - 1)
-
-        dataArray = []
-        for i in range(0, SAMPLE_COUNT_Z):
-            newRow = []
-            # Keep values within range bounds, since just adding step can
-            # cause minor drift due to the rounding errors.
-            z = min(SAMPLE_MAX, (i * stepZ + SAMPLE_MIN))
-            for j in range(0, SAMPLE_COUNT_X):
-                x = min(SAMPLE_MAX, (j * stepX + SAMPLE_MIN))
-                R = sqrt(z * z + x * x) + 0.01
-                y = (sin(R) / R + 0.24) * 1.61
-                item = QSurfaceDataItem(QVector3D(x, y, z))
-                newRow.append(item)
-            dataArray.append(newRow)
-        self._sqrtSinProxy.resetArray(dataArray)
-
-    @Slot(bool)
-    def enableSqrtSinModel(self, enable):
-        if enable:
-            self._sqrtSinSeries.setDrawMode(QSurface3DSeries.DrawSurfaceAndWireframe)
-            self._sqrtSinSeries.setFlatShadingEnabled(True)
-
-            self._graph.axisX().setLabelFormat("%.2f")
-            self._graph.axisZ().setLabelFormat("%.2f")
-            self._graph.axisX().setRange(SAMPLE_MIN, SAMPLE_MAX)
-            self._graph.axisY().setRange(0.0, 2.0)
-            self._graph.axisZ().setRange(SAMPLE_MIN, SAMPLE_MAX)
-            self._graph.axisX().setLabelAutoRotation(30.0)
-            self._graph.axisY().setLabelAutoRotation(90.0)
-            self._graph.axisZ().setLabelAutoRotation(30.0)
-
-            self._graph.removeSeries(self._heightMapSeriesOne)
-            self._graph.removeSeries(self._heightMapSeriesTwo)
-            self._graph.removeSeries(self._heightMapSeriesThree)
-            self._graph.removeSeries(self._topography)
-            self._graph.removeSeries(self._highlight)
-
-            self._graph.addSeries(self._sqrtSinSeries)
-
-            self._titleLabel.setVisible(False)
-            self._graph.axisX().setTitleVisible(False)
-            self._graph.axisY().setTitleVisible(False)
-            self._graph.axisZ().setTitleVisible(False)
-
-            self._graph.axisX().setTitle("")
-            self._graph.axisY().setTitle("")
-            self._graph.axisZ().setTitle("")
-
-            self._graph.setActiveInputHandler(self._defaultInputHandler)
-
-            # Reset range sliders for Sqrt & Sin
-            self._rangeMinX = SAMPLE_MIN
-            self._rangeMinZ = SAMPLE_MIN
-            self._stepX = (SAMPLE_MAX - SAMPLE_MIN) / float(SAMPLE_COUNT_X - 1)
-            self._stepZ = (SAMPLE_MAX - SAMPLE_MIN) / float(SAMPLE_COUNT_Z - 1)
-            self._axisMinSliderX.setMinimum(0)
-            self._axisMinSliderX.setMaximum(SAMPLE_COUNT_X - 2)
-            self._axisMinSliderX.setValue(0)
-            self._axisMaxSliderX.setMinimum(1)
-            self._axisMaxSliderX.setMaximum(SAMPLE_COUNT_X - 1)
-            self._axisMaxSliderX.setValue(SAMPLE_COUNT_X - 1)
-            self._axisMinSliderZ.setMinimum(0)
-            self._axisMinSliderZ.setMaximum(SAMPLE_COUNT_Z - 2)
-            self._axisMinSliderZ.setValue(0)
-            self._axisMaxSliderZ.setMinimum(1)
-            self._axisMaxSliderZ.setMaximum(SAMPLE_COUNT_Z - 1)
-            self._axisMaxSliderZ.setValue(SAMPLE_COUNT_Z - 1)
-
-    @Slot(bool)
-    def enableHeightMapModel(self, enable):
-        if enable:
-            self._heightMapSeriesOne.setDrawMode(QSurface3DSeries.DrawSurface)
-            self._heightMapSeriesOne.setFlatShadingEnabled(False)
-            self._heightMapSeriesTwo.setDrawMode(QSurface3DSeries.DrawSurface)
-            self._heightMapSeriesTwo.setFlatShadingEnabled(False)
-            self._heightMapSeriesThree.setDrawMode(QSurface3DSeries.DrawSurface)
-            self._heightMapSeriesThree.setFlatShadingEnabled(False)
-
-            self._graph.axisX().setLabelFormat("%.1f N")
-            self._graph.axisZ().setLabelFormat("%.1f E")
-            self._graph.axisX().setRange(34.0, 40.0)
-            self._graph.axisY().setAutoAdjustRange(True)
-            self._graph.axisZ().setRange(18.0, 24.0)
-
-            self._graph.axisX().setTitle("Latitude")
-            self._graph.axisY().setTitle("Height")
-            self._graph.axisZ().setTitle("Longitude")
-
-            self._graph.removeSeries(self._sqrtSinSeries)
-            self._graph.removeSeries(self._topography)
-            self._graph.removeSeries(self._highlight)
-            self._graph.addSeries(self._heightMapSeriesOne)
-            self._graph.addSeries(self._heightMapSeriesTwo)
-            self._graph.addSeries(self._heightMapSeriesThree)
-
-            self._graph.setActiveInputHandler(self._defaultInputHandler)
-
-            self._titleLabel.setVisible(True)
-            self._graph.axisX().setTitleVisible(True)
-            self._graph.axisY().setTitleVisible(True)
-            self._graph.axisZ().setTitleVisible(True)
-
-            # Reset range sliders for height map
-            mapGridCountX = self._heightMapWidth / HEIGHTMAP_GRID_STEP_X
-            mapGridCountZ = self._heightMapHeight / HEIGHTMAP_GRID_STEP_Z
-            self._rangeMinX = 34.0
-            self._rangeMinZ = 18.0
-            self._stepX = 6.0 / float(mapGridCountX - 1)
-            self._stepZ = 6.0 / float(mapGridCountZ - 1)
-            self._axisMinSliderX.setMinimum(0)
-            self._axisMinSliderX.setMaximum(mapGridCountX - 2)
-            self._axisMinSliderX.setValue(0)
-            self._axisMaxSliderX.setMinimum(1)
-            self._axisMaxSliderX.setMaximum(mapGridCountX - 1)
-            self._axisMaxSliderX.setValue(mapGridCountX - 1)
-            self._axisMinSliderZ.setMinimum(0)
-            self._axisMinSliderZ.setMaximum(mapGridCountZ - 2)
-            self._axisMinSliderZ.setValue(0)
-            self._axisMaxSliderZ.setMinimum(1)
-            self._axisMaxSliderZ.setMaximum(mapGridCountZ - 1)
-            self._axisMaxSliderZ.setValue(mapGridCountZ - 1)
-
-    @Slot(bool)
-    def enableTopographyModel(self, enable):
-        if enable:
-            self._graph.axisX().setLabelFormat("%i")
-            self._graph.axisZ().setLabelFormat("%i")
-            self._graph.axisX().setRange(0.0, AREA_WIDTH)
-            self._graph.axisY().setRange(100.0, AREA_WIDTH * ASPECT_RATIO)
-            self._graph.axisZ().setRange(0.0, AREA_HEIGHT)
-            self._graph.axisX().setLabelAutoRotation(30.0)
-            self._graph.axisY().setLabelAutoRotation(90.0)
-            self._graph.axisZ().setLabelAutoRotation(30.0)
-
-            self._graph.removeSeries(self._heightMapSeriesOne)
-            self._graph.removeSeries(self._heightMapSeriesTwo)
-            self._graph.removeSeries(self._heightMapSeriesThree)
-            self._graph.addSeries(self._topography)
-            self._graph.addSeries(self._highlight)
-
-            self._titleLabel.setVisible(False)
-            self._graph.axisX().setTitleVisible(False)
-            self._graph.axisY().setTitleVisible(False)
-            self._graph.axisZ().setTitleVisible(False)
-
-            self._graph.axisX().setTitle("")
-            self._graph.axisY().setTitle("")
-            self._graph.axisZ().setTitle("")
-
-            self._graph.setActiveInputHandler(self._customInputHandler)
-
-            # Reset range sliders for topography map
-            self._rangeMinX = 0.0
-            self._rangeMinZ = 0.0
-            self._stepX = 1.0
-            self._stepZ = 1.0
-            self._axisMinSliderX.setMinimum(0)
-            self._axisMinSliderX.setMaximum(AREA_WIDTH - 200)
-            self._axisMinSliderX.setValue(0)
-            self._axisMaxSliderX.setMinimum(200)
-            self._axisMaxSliderX.setMaximum(AREA_WIDTH)
-            self._axisMaxSliderX.setValue(AREA_WIDTH)
-            self._axisMinSliderZ.setMinimum(0)
-            self._axisMinSliderZ.setMaximum(AREA_HEIGHT - 200)
-            self._axisMinSliderZ.setValue(0)
-            self._axisMaxSliderZ.setMinimum(200)
-            self._axisMaxSliderZ.setMaximum(AREA_HEIGHT)
-            self._axisMaxSliderZ.setValue(AREA_HEIGHT)
-
-    def adjustXMin(self, min):
-        minX = self._stepX * float(min) + self._rangeMinX
-
-        max = self._axisMaxSliderX.value()
-        if min >= max:
-            max = min + 1
-            self._axisMaxSliderX.setValue(max)
-
-        maxX = self._stepX * max + self._rangeMinX
-
-        self.setAxisXRange(minX, maxX)
-
-    def adjustXMax(self, max):
-        maxX = self._stepX * float(max) + self._rangeMinX
-
-        min = self._axisMinSliderX.value()
-        if max <= min:
-            min = max - 1
-            self._axisMinSliderX.setValue(min)
-
-        minX = self._stepX * min + self._rangeMinX
-
-        self.setAxisXRange(minX, maxX)
-
-    def adjustZMin(self, min):
-        minZ = self._stepZ * float(min) + self._rangeMinZ
-
-        max = self._axisMaxSliderZ.value()
-        if min >= max:
-            max = min + 1
-            self._axisMaxSliderZ.setValue(max)
-
-        maxZ = self._stepZ * max + self._rangeMinZ
-
-        self.setAxisZRange(minZ, maxZ)
-
-    def adjustZMax(self, max):
-        maxX = self._stepZ * float(max) + self._rangeMinZ
-
-        min = self._axisMinSliderZ.value()
-        if max <= min:
-            min = max - 1
-            self._axisMinSliderZ.setValue(min)
-
-        minX = self._stepZ * min + self._rangeMinZ
-
-        self.setAxisZRange(minX, maxX)
-
-    def setAxisXRange(self, min, max):
-        self._graph.axisX().setRange(min, max)
-
-    def setAxisZRange(self, min, max):
-        self._graph.axisZ().setRange(min, max)
-
-    def setBlackToYellowGradient(self):
-        gr = QLinearGradient()
-        gr.setColorAt(0.0, Qt.black)
-        gr.setColorAt(0.33, Qt.blue)
-        gr.setColorAt(0.67, Qt.red)
-        gr.setColorAt(1.0, Qt.yellow)
-
-        self._sqrtSinSeries.setBaseGradient(gr)
-        self._sqrtSinSeries.setColorStyle(Q3DTheme.ColorStyleRangeGradient)
-
-    def setGreenToRedGradient(self):
-        gr = QLinearGradient()
-        gr.setColorAt(0.0, Qt.darkGreen)
-        gr.setColorAt(0.5, Qt.yellow)
-        gr.setColorAt(0.8, Qt.red)
-        gr.setColorAt(1.0, Qt.darkRed)
-
-        self._sqrtSinSeries.setBaseGradient(gr)
-        self._sqrtSinSeries.setColorStyle(Q3DTheme.ColorStyleRangeGradient)
-
-    @Slot(bool)
-    def toggleItemOne(self, show):
-        positionOne = QVector3D(39.0, 77.0, 19.2)
-        positionOnePipe = QVector3D(39.0, 45.0, 19.2)
-        positionOneLabel = QVector3D(39.0, 107.0, 19.2)
-        if show:
-            color = QImage(2, 2, QImage.Format_RGB32)
-            color.fill(Qt.red)
-            file_name = os.fspath(self._data_path / "oilrig.mesh")
-            item = QCustom3DItem(file_name, positionOne,
-                                 QVector3D(0.025, 0.025, 0.025),
-                                 QQuaternion.fromAxisAndAngle(0.0, 1.0, 0.0, 45.0),
-                                 color)
-            self._graph.addCustomItem(item)
-            file_name = os.fspath(self._data_path / "pipe.mesh")
-            item = QCustom3DItem(file_name, positionOnePipe,
-                                 QVector3D(0.005, 0.5, 0.005), QQuaternion(),
-                                 color)
-            item.setShadowCasting(False)
-            self._graph.addCustomItem(item)
-
-            label = QCustom3DLabel()
-            label.setText("Oil Rig One")
-            label.setPosition(positionOneLabel)
-            label.setScaling(QVector3D(1.0, 1.0, 1.0))
-            self._graph.addCustomItem(label)
-        else:
-            self.resetSelection()
-            self._graph.removeCustomItemAt(positionOne)
-            self._graph.removeCustomItemAt(positionOnePipe)
-            self._graph.removeCustomItemAt(positionOneLabel)
-
-    @Slot(bool)
-    def toggleItemTwo(self, show):
-        positionTwo = QVector3D(34.5, 77.0, 23.4)
-        positionTwoPipe = QVector3D(34.5, 45.0, 23.4)
-        positionTwoLabel = QVector3D(34.5, 107.0, 23.4)
-        if show:
-            color = QImage(2, 2, QImage.Format_RGB32)
-            color.fill(Qt.red)
-            item = QCustom3DItem()
-            file_name = os.fspath(self._data_path / "oilrig.mesh")
-            item.setMeshFile(file_name)
-            item.setPosition(positionTwo)
-            item.setScaling(QVector3D(0.025, 0.025, 0.025))
-            item.setRotation(QQuaternion.fromAxisAndAngle(0.0, 1.0, 0.0, 25.0))
-            item.setTextureImage(color)
-            self._graph.addCustomItem(item)
-            file_name = os.fspath(self._data_path / "pipe.mesh")
-            item = QCustom3DItem(file_name, positionTwoPipe,
-                                 QVector3D(0.005, 0.5, 0.005), QQuaternion(),
-                                 color)
-            item.setShadowCasting(False)
-            self._graph.addCustomItem(item)
-
-            label = QCustom3DLabel()
-            label.setText("Oil Rig Two")
-            label.setPosition(positionTwoLabel)
-            label.setScaling(QVector3D(1.0, 1.0, 1.0))
-            self._graph.addCustomItem(label)
-        else:
-            self.resetSelection()
-            self._graph.removeCustomItemAt(positionTwo)
-            self._graph.removeCustomItemAt(positionTwoPipe)
-            self._graph.removeCustomItemAt(positionTwoLabel)
-
-    @Slot(bool)
-    def toggleItemThree(self, show):
-        positionThree = QVector3D(34.5, 86.0, 19.1)
-        positionThreeLabel = QVector3D(34.5, 116.0, 19.1)
-        if show:
-            color = QImage(2, 2, QImage.Format_RGB32)
-            color.fill(Qt.darkMagenta)
-            item = QCustom3DItem()
-            file_name = os.fspath(self._data_path / "refinery.mesh")
-            item.setMeshFile(file_name)
-            item.setPosition(positionThree)
-            item.setScaling(QVector3D(0.04, 0.04, 0.04))
-            item.setRotation(QQuaternion.fromAxisAndAngle(0.0, 1.0, 0.0, 75.0))
-            item.setTextureImage(color)
-            self._graph.addCustomItem(item)
-
-            label = QCustom3DLabel()
-            label.setText("Refinery")
-            label.setPosition(positionThreeLabel)
-            label.setScaling(QVector3D(1.0, 1.0, 1.0))
-            self._graph.addCustomItem(label)
-        else:
-            self.resetSelection()
-            self._graph.removeCustomItemAt(positionThree)
-            self._graph.removeCustomItemAt(positionThreeLabel)
-
-    @Slot(bool)
-    def toggleSeeThrough(self, seethrough):
-        s0 = self._graph.seriesList()[0]
-        s1 = self._graph.seriesList()[1]
-        if seethrough:
-            s0.setDrawMode(QSurface3DSeries.DrawWireframe)
-            s1.setDrawMode(QSurface3DSeries.DrawWireframe)
-        else:
-            s0.setDrawMode(QSurface3DSeries.DrawSurface)
-            s1.setDrawMode(QSurface3DSeries.DrawSurface)
-
-    @Slot(bool)
-    def toggleOilHighlight(self, highlight):
-        s2 = self._graph.seriesList()[2]
-        if highlight:
-            grThree = QLinearGradient()
-            grThree.setColorAt(0.0, Qt.black)
-            grThree.setColorAt(0.05, Qt.red)
-            s2.setBaseGradient(grThree)
-        else:
-            grThree = QLinearGradient()
-            grThree.setColorAt(0.0, Qt.white)
-            grThree.setColorAt(0.05, Qt.black)
-            s2.setBaseGradient(grThree)
-
-    @Slot(bool)
-    def toggleShadows(self, shadows):
-        sq = (QAbstract3DGraph.ShadowQualityMedium
-              if shadows else QAbstract3DGraph.ShadowQualityNone)
-        self._graph.setShadowQuality(sq)
-
-    @Slot(bool)
-    def toggleSurfaceTexture(self, enable):
-        if enable:
-            file_name = os.fspath(self._data_path / "maptexture.jpg")
-            self._topography.setTextureFile(file_name)
-        else:
-            self._topography.setTextureFile("")
-
-    def handleElementSelected(self, type):
-        self.resetSelection()
-        if type == QAbstract3DGraph.ElementCustomItem:
-            item = self._graph.selectedCustomItem()
-            text = ""
-            if isinstance(item, QCustom3DItem):
-                text += "Custom label: "
-            else:
-                file = item.meshFile().split("/")[-1]
-                text += f"{file}: "
-
-            text += str(self._graph.selectedCustomItemIndex())
-            self._textField.setText(text)
-            self._previouslyAnimatedItem = item
-            self._previousScaling = item.scaling()
-            self._selectionAnimation.setTargetObject(item)
-            self._selectionAnimation.setStartValue(item.scaling())
-            self._selectionAnimation.setEndValue(item.scaling() * 1.5)
-            self._selectionAnimation.start()
-        elif type == QAbstract3DGraph.ElementSeries:
-            text = "Surface ("
-            series = self._graph.selectedSeries()
-            if series:
-                point = series.selectedPoint()
-                text += f"{point.x()}, {point.y()}"
-            text += ")"
-            self._textField.setText(text)
-        elif (type.value > QAbstract3DGraph.ElementSeries.value
-              and type < QAbstract3DGraph.ElementCustomItem.value):
-            index = self._graph.selectedLabelIndex()
-            text = ""
-            if type == QAbstract3DGraph.ElementAxisXLabel:
-                text += "Axis X label: "
-            elif type == QAbstract3DGraph.ElementAxisYLabel:
-                text += "Axis Y label: "
-            else:
-                text += "Axis Z label: "
-            text += str(index)
-            self._textField.setText(text)
-        else:
-            self._textField.setText("Nothing")
-
-    def resetSelection(self):
-        self._selectionAnimation.stop()
-        if self._previouslyAnimatedItem:
-            self._previouslyAnimatedItem.setScaling(self._previousScaling)
-        self._previouslyAnimatedItem = None
-
-    def toggleModeNone(self):
-        self._graph.setSelectionMode(QAbstract3DGraph.SelectionNone)
-
-    def toggleModeItem(self):
-        self._graph.setSelectionMode(QAbstract3DGraph.SelectionItem)
-
-    def toggleModeSliceRow(self):
-        sm = (QAbstract3DGraph.SelectionItemAndRow
-              | QAbstract3DGraph.SelectionSlice
-              | QAbstract3DGraph.SelectionMultiSeries)
-        self._graph.setSelectionMode(sm)
-
-    def toggleModeSliceColumn(self):
-        sm = (QAbstract3DGraph.SelectionItemAndColumn
-              | QAbstract3DGraph.SelectionSlice
-              | QAbstract3DGraph.SelectionMultiSeries)
-        self._graph.setSelectionMode(sm)
-
-    def setAxisMinSliderX(self, slider):
-        self._axisMinSliderX = slider
-
-    def setAxisMaxSliderX(self, slider):
-        self._axisMaxSliderX = slider
-
-    def setAxisMinSliderZ(self, slider):
-        self._axisMinSliderZ = slider
-
-    def setAxisMaxSliderZ(self, slider):
-        self._axisMaxSliderZ = slider
diff --git a/examples/graphs/widgetgallery/topographicseries.py b/examples/graphs/widgetgallery/topographicseries.py
deleted file mode 100644 (file)
index 4f286a2..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from PySide6.QtCore import Qt
-from PySide6.QtGui import QImage, QVector3D
-from PySide6.QtGraphs import (QSurface3DSeries, QSurfaceDataItem)
-
-
-# Value used to encode height data as RGB value on PNG file
-PACKING_FACTOR = 11983.0
-
-
-class TopographicSeries(QSurface3DSeries):
-
-    def __init__(self):
-        super().__init__()
-        self._sampleCountX = 0.0
-        self._sampleCountZ = 0.0
-        self.setDrawMode(QSurface3DSeries.DrawSurface)
-        self.setFlatShadingEnabled(True)
-        self.setBaseColor(Qt.white)
-
-    def sampleCountX(self):
-        return self._sampleCountX
-
-    def sampleCountZ(self):
-        return self._sampleCountZ
-
-    def setTopographyFile(self, file, width, height):
-        heightMapImage = QImage(file)
-        bits = heightMapImage.bits()
-        imageHeight = heightMapImage.height()
-        imageWidth = heightMapImage.width()
-        widthBits = imageWidth * 4
-        stepX = width / float(imageWidth)
-        stepZ = height / float(imageHeight)
-
-        dataArray = []
-        for i in range(0, imageHeight):
-            p = i * widthBits
-            z = height - float(i) * stepZ
-            newRow = []
-            for j in range(0, imageWidth):
-                aa = bits[p + 0]
-                rr = bits[p + 1]
-                gg = bits[p + 2]
-                color = (gg << 16) + (rr << 8) + aa
-                y = float(color) / PACKING_FACTOR
-                item = QSurfaceDataItem(QVector3D(float(j) * stepX, y, z))
-                newRow.append(item)
-                p += 4
-            dataArray.append(newRow)
-
-        self.dataProxy().resetArray(dataArray)
-
-        self._sampleCountX = float(imageWidth)
-        self._sampleCountZ = float(imageHeight)
diff --git a/examples/graphs/widgetgallery/variantbardatamapping.py b/examples/graphs/widgetgallery/variantbardatamapping.py
deleted file mode 100644 (file)
index 50bdefa..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from PySide6.QtCore import QObject, Signal
-
-
-class VariantBarDataMapping(QObject):
-
-    rowIndexChanged = Signal()
-    columnIndexChanged = Signal()
-    valueIndexChanged = Signal()
-    rowCategoriesChanged = Signal()
-    columnCategoriesChanged = Signal()
-    mappingChanged = Signal()
-
-    def __init__(self, rowIndex, columnIndex, valueIndex,
-                 rowCategories=[], columnCategories=[]):
-        super().__init__(None)
-        self._rowIndex = rowIndex
-        self._columnIndex = columnIndex
-        self._valueIndex = valueIndex
-        self._rowCategories = rowCategories
-        self._columnCategories = columnCategories
-
-    def setRowIndex(self, index):
-        self._rowIndex = index
-        self.mappingChanged.emit()
-
-    def rowIndex(self):
-        return self._rowIndex
-
-    def setColumnIndex(self, index):
-        self._columnIndex = index
-        self.mappingChanged.emit()
-
-    def columnIndex(self):
-        return self._columnIndex
-
-    def setValueIndex(self, index):
-        self._valueIndex = index
-        self.mappingChanged.emit()
-
-    def valueIndex(self):
-        return self._valueIndex
-
-    def setRowCategories(self, categories):
-        self._rowCategories = categories
-        self.mappingChanged.emit()
-
-    def rowCategories(self):
-        return self._rowCategories
-
-    def setColumnCategories(self, categories):
-        self._columnCategories = categories
-        self.mappingChanged.emit()
-
-    def columnCategories(self):
-        return self._columnCategories
-
-    def remap(self, rowIndex, columnIndex, valueIndex,
-              rowCategories=[], columnCategories=[]):
-        self._rowIndex = rowIndex
-        self._columnIndex = columnIndex
-        self._valueIndex = valueIndex
-        self._rowCategories = rowCategories
-        self._columnCategories = columnCategories
-        self.mappingChanged.emit()
diff --git a/examples/graphs/widgetgallery/variantbardataproxy.py b/examples/graphs/widgetgallery/variantbardataproxy.py
deleted file mode 100644 (file)
index 5ab2a2c..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from PySide6.QtCore import Slot
-from PySide6.QtGraphs import QBarDataProxy, QBarDataItem
-
-
-class VariantBarDataProxy(QBarDataProxy):
-
-    def __init__(self):
-        super().__init__()
-        self._dataSet = None
-        self._mapping = None
-
-    def setDataSet(self, newSet):
-        if self._dataSet:
-            self._dataSet.itemsAdded.disconnect(self.handleItemsAdded)
-            self._dataSet.dataCleared.disconnect(self.handleDataCleared)
-
-        self._dataSet = newSet
-
-        if self._dataSet:
-            self._dataSet.itemsAdded.connect(self.handleItemsAdded)
-            self._dataSet.dataCleared.connect(self.handleDataCleared)
-        self.resolveDataSet()
-
-    def dataSet(self):
-        return self._dataSet.data()
-
-    # Map key (row, column, value) to value index in data item (VariantItem).
-    # Doesn't gain ownership of mapping, but does connect to it to listen for
-    # mapping changes. Modifying mapping that is set to proxy will trigger
-    # dataset re-resolving.
-    def setMapping(self, mapping):
-        if self._mapping:
-            self._mapping.mappingChanged.disconnect(self.handleMappingChanged)
-
-        self._mapping = mapping
-
-        if self._mapping:
-            self._mapping.mappingChanged.connect(self.handleMappingChanged)
-
-        self.resolveDataSet()
-
-    def mapping(self):
-        return self._mapping.data()
-
-    @Slot(int, int)
-    def handleItemsAdded(self, index, count):
-        # Resolve new items
-        self.resolveDataSet()
-
-    @Slot()
-    def handleDataCleared(self):
-        # Data cleared, reset array
-        self.resetArray(None)
-
-    @Slot()
-    def handleMappingChanged(self):
-        self.resolveDataSet()
-
-    # Resolve entire dataset into QBarDataArray.
-    def resolveDataSet(self):
-        # If we have no data or mapping, or the categories are not defined,
-        # simply clear the array
-        if (not self._dataSet or not self._mapping
-                or not self._mapping.rowCategories()
-                or not self._mapping.columnCategories()):
-            self.resetArray()
-            return
-
-        itemList = self._dataSet.itemList()
-
-        rowIndex = self._mapping.rowIndex()
-        columnIndex = self._mapping.columnIndex()
-        valueIndex = self._mapping.valueIndex()
-        rowList = self._mapping.rowCategories()
-        columnList = self._mapping.columnCategories()
-
-        # Sort values into rows and columns
-        itemValueMap = {}
-        for item in itemList:
-            key = str(item[rowIndex])
-            v = itemValueMap.get(key)
-            if not v:
-                v = {}
-                itemValueMap[key] = v
-            v[str(item[columnIndex])] = float(item[valueIndex])
-
-        # Create a new data array in format the parent class understands
-        newProxyArray = []
-        for rowKey in rowList:
-            newProxyRow = []
-            for i in range(0, len(columnList)):
-                item = QBarDataItem(itemValueMap[rowKey][columnList[i]])
-                newProxyRow.append(item)
-            newProxyArray.append(newProxyRow)
-
-        # Finally, reset the data array in the parent class
-        self.resetArray(newProxyArray)
diff --git a/examples/graphs/widgetgallery/variantdataset.py b/examples/graphs/widgetgallery/variantdataset.py
deleted file mode 100644 (file)
index 752bc38..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-from PySide6.QtCore import QObject, Signal
-
-
-class VariantDataSet(QObject):
-
-    itemsAdded = Signal(int, int)
-    dataCleared = Signal()
-
-    def __init__(self):
-        super().__init__()
-        self._variantData = []
-
-    def clear(self):
-        for item in self._variantData:
-            item.clear()
-            del item
-
-        self._variantData.clear()
-        self.dataCleared.emit()
-
-    def addItem(self, item):
-        self._variantData.append(item)
-        addIndex = len(self._variantData)
-
-        self.itemsAdded.emit(addIndex, 1)
-        return addIndex
-
-    def addItems(self, itemList):
-        newCount = len(itemList)
-        addIndex = len(self._variantData)
-        self._variantData.extend(itemList)
-        self.itemsAdded.emit(addIndex, newCount)
-        return addIndex
-
-    def itemList(self):
-        return self._variantData
diff --git a/examples/graphs/widgetgallery/widgetgallery.pyproject b/examples/graphs/widgetgallery/widgetgallery.pyproject
deleted file mode 100644 (file)
index 581b214..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-    "files": ["main.py",
-              "axesinputhandler.py",
-              "bargraph.py",
-              "custominputhandler.py",
-              "graphmodifier.py",
-              "highlightseries.py",
-              "rainfalldata.py",
-              "scatterdatamodifier.py",
-              "scattergraph.py",
-              "surfacegraph.py",
-              "surfacegraphmodifier.py",
-              "topographicseries.py",
-              "variantbardatamapping.py",
-              "variantbardataproxy.py",
-              "variantdataset.py",
-              "data/layer_1.png",
-              "data/layer_2.png",
-              "data/layer_3.png",
-              "data/license.txt",
-              "data/maptexture.jpg",
-              "data/narrowarrow.mesh",
-              "data/oilrig.mesh",
-              "data/pipe.mesh",
-              "data/raindata.txt",
-              "data/refinery.mesh",
-              "data/topography.png"
-]
-}
index f38f9af63513456649ed7784c184c83a66d2cd3d..defbc46ef0d2d2e00e1d6c0ff097655456c83acb 100644 (file)
@@ -1,3 +1,5 @@
+.. _rhi-window-example:
+
 RHI Window Example
 ==================
 
@@ -28,13 +30,7 @@ platform/API specifics or correctly handling ``QExposeEvent`` and resize events
 for the window are all managed by Qt Quick. Whereas in this example, all that
 is managed and taken care of by the application itself.
 
-.. note:: For ``QWidget``-based applications in particular, it should be noted
-    that ``QWidget::createWindowContainer()`` allows embedding a ``QWindow``
-    (backed by a native window) into the widget-based user interface. Therefore,
-    the ``HelloWindow`` class from this example is reusable in ``QWidget``-based
-    applications, assuming the necessary initialization from ``main()`` is in place
-    as well.
-
+.. note:: For ``QWidget``-based applications, see the :ref:`rhi-widget-example`.
 
 Shaders
 -------
index 5be9b0d6e09b6f997aeb7b1b7bd8bbe0051f906a..06d52f68a8e45385bbed97317efabf09c8766f99 100644 (file)
@@ -177,11 +177,18 @@ class AudioTest(QMainWindow):
         self.m_audioSink.start(self.m_generator)
         self.m_volumeSlider.setValue(self.m_audioSink.volume() * 100)
 
-    @Slot(int)
-    def device_changed(self, index):
+    def closeEvent(self, e):
+        self.stop()
+        e.accept()
+
+    def stop(self):
         self.m_pullTimer.stop()
         self.m_generator.stop()
         self.m_audioSink.stop()
+
+    @Slot(int)
+    def device_changed(self, index):
+        self.stop()
         self.m_device = self.m_deviceBox.itemData(index)
 
         self.create_audio_output()
index bc2d606c09341fa5c370a087eef3e6582f486e94..a78beb584fca07343527961270ac90736acfa7c6 100644 (file)
@@ -25,7 +25,7 @@ from PySide6.QtWidgets import (QApplication, QComboBox, QPushButton, QSlider, QV
 
 is_android = os.environ.get('ANDROID_ARGUMENT')
 
-if is_android:
+if is_android or sys.platform == "darwin":
     from PySide6.QtCore import QMicrophonePermission
 
 
@@ -93,7 +93,13 @@ class InputTest(QWidget):
 
     @Slot()
     def initialize(self):
-        if is_android:
+        if is_android or sys.platform == "darwin":
+            is_nuitka = "__compiled__" in globals()
+            if not is_nuitka and sys.platform == "darwin":
+                print("This example does not work on macOS when Python is run in interpreted mode."
+                      "For this example to work on macOS, package the example using pyside6-deploy"
+                      "For more information, read `Notes for Developer` in the documentation")
+                sys.exit(0)
             permission = QMicrophonePermission()
             permission_status = qApp.checkPermission(permission)  # noqa: F821
             if permission_status == Qt.PermissionStatus.Undetermined:
index f66f28a21c8136fd27a4baa07a3eeee59a374bbd..fa379c8076aa5492f9175b65c97ee5f2285fbc91 100644 (file)
@@ -2,6 +2,7 @@
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
 
 import os
+import sys
 from pathlib import Path
 
 from PySide6.QtMultimedia import (QAudioInput, QCamera, QCameraDevice,
@@ -16,8 +17,10 @@ from metadatadialog import MetaDataDialog
 from imagesettings import ImageSettings
 from videosettings import VideoSettings, is_android
 
-if is_android:
+if is_android or sys.platform == "darwin":
     from PySide6.QtCore import QMicrophonePermission, QCameraPermission
+
+if is_android:
     from ui_camera_mobile import Ui_Camera
 else:
     from ui_camera import Ui_Camera
@@ -60,7 +63,14 @@ class Camera(QMainWindow):
 
     @Slot()
     def initialize(self):
-        if is_android:
+        if is_android or sys.platform == "darwin":
+            is_nuitka = "__compiled__" in globals()
+            if not is_nuitka and sys.platform == "darwin":
+                print("This example does not work on macOS when Python is run in interpreted mode."
+                      "For this example to work on macOS, package the example using pyside6-deploy"
+                      "For more information, read `Notes for Developer` in the documentation")
+                sys.exit(0)
+
             # camera
             cam_permission = QCameraPermission()
             cam_permission_status = qApp.checkPermission(cam_permission)  # noqa: F821
index 92e115c770e5910e41612dca6f0af68a8a96d675..690cf3352f801a669a2cc89a7705f0f12de4a457 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'camera.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -47,7 +47,7 @@ class Ui_Camera(object):
         self.tab_2.setObjectName(u"tab_2")
         self.gridLayout = QGridLayout(self.tab_2)
         self.gridLayout.setObjectName(u"gridLayout")
-        self.verticalSpacer_2 = QSpacerItem(20, 161, QSizePolicy.Minimum, QSizePolicy.Expanding)
+        self.verticalSpacer_2 = QSpacerItem(20, 161, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
 
         self.gridLayout.addItem(self.verticalSpacer_2, 3, 0, 1, 1)
 
@@ -92,7 +92,7 @@ class Ui_Camera(object):
 
         self.gridLayout_2.addWidget(self.stopButton, 2, 0, 1, 1)
 
-        self.verticalSpacer = QSpacerItem(20, 76, QSizePolicy.Minimum, QSizePolicy.Expanding)
+        self.verticalSpacer = QSpacerItem(20, 76, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
 
         self.gridLayout_2.addItem(self.verticalSpacer, 3, 0, 1, 1)
 
@@ -114,7 +114,7 @@ class Ui_Camera(object):
 
         self.stackedWidget = QStackedWidget(self.centralwidget)
         self.stackedWidget.setObjectName(u"stackedWidget")
-        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(1)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.stackedWidget.sizePolicy().hasHeightForWidth())
@@ -147,7 +147,7 @@ class Ui_Camera(object):
         self.gridLayout_4.setObjectName(u"gridLayout_4")
         self.lastImagePreviewLabel = QLabel(self.previewPage)
         self.lastImagePreviewLabel.setObjectName(u"lastImagePreviewLabel")
-        sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
+        sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.MinimumExpanding)
         sizePolicy1.setHorizontalStretch(0)
         sizePolicy1.setVerticalStretch(0)
         sizePolicy1.setHeightForWidth(self.lastImagePreviewLabel.sizePolicy().hasHeightForWidth())
index 9feab3d682a83f37a5b4f72d774ffeadf2ff54aa..5cdd81f1e1ac318c958b60f29b2037f03ed8c858 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'camera_mobile.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.2
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -42,7 +42,7 @@ class Ui_Camera(object):
         self.gridLayout_3.setObjectName(u"gridLayout_3")
         self.captureWidget = QTabWidget(self.centralwidget)
         self.captureWidget.setObjectName(u"captureWidget")
-        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.captureWidget.sizePolicy().hasHeightForWidth())
@@ -63,7 +63,7 @@ class Ui_Camera(object):
 
         self.label = QLabel(self.tab_2)
         self.label.setObjectName(u"label")
-        sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
+        sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
         sizePolicy1.setHorizontalStretch(0)
         sizePolicy1.setVerticalStretch(0)
         sizePolicy1.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
@@ -109,7 +109,7 @@ class Ui_Camera(object):
 
         self.verticalLayout_2 = QVBoxLayout()
         self.verticalLayout_2.setObjectName(u"verticalLayout_2")
-        self.verticalSpacer = QSpacerItem(20, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)
+        self.verticalSpacer = QSpacerItem(20, 10, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
 
         self.verticalLayout_2.addItem(self.verticalSpacer)
 
@@ -137,7 +137,7 @@ class Ui_Camera(object):
 
         self.stackedWidget = QStackedWidget(self.centralwidget)
         self.stackedWidget.setObjectName(u"stackedWidget")
-        sizePolicy2 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
         sizePolicy2.setHorizontalStretch(1)
         sizePolicy2.setVerticalStretch(0)
         sizePolicy2.setHeightForWidth(self.stackedWidget.sizePolicy().hasHeightForWidth())
@@ -160,7 +160,7 @@ class Ui_Camera(object):
         self.gridLayout_5.setObjectName(u"gridLayout_5")
         self.viewfinder = QVideoWidget(self.viewfinderPage)
         self.viewfinder.setObjectName(u"viewfinder")
-        sizePolicy3 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
         sizePolicy3.setHorizontalStretch(0)
         sizePolicy3.setVerticalStretch(0)
         sizePolicy3.setHeightForWidth(self.viewfinder.sizePolicy().hasHeightForWidth())
@@ -175,7 +175,7 @@ class Ui_Camera(object):
         self.gridLayout_4.setObjectName(u"gridLayout_4")
         self.lastImagePreviewLabel = QLabel(self.previewPage)
         self.lastImagePreviewLabel.setObjectName(u"lastImagePreviewLabel")
-        sizePolicy4 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
+        sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.MinimumExpanding)
         sizePolicy4.setHorizontalStretch(0)
         sizePolicy4.setVerticalStretch(0)
         sizePolicy4.setHeightForWidth(self.lastImagePreviewLabel.sizePolicy().hasHeightForWidth())
index aa7505f8fb65dda7108107aeec52d24a1539dfc3..a3fba7789db60f886dfcd8ac6a094162b415ca08 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'imagesettings.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -65,7 +65,7 @@ class Ui_ImageSettingsUi(object):
 
         self.gridLayout.addWidget(self.groupBox_2, 0, 0, 1, 1)
 
-        self.verticalSpacer = QSpacerItem(20, 14, QSizePolicy.Minimum, QSizePolicy.Expanding)
+        self.verticalSpacer = QSpacerItem(20, 14, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
 
         self.gridLayout.addItem(self.verticalSpacer, 1, 0, 1, 1)
 
index c84c93d786b54c0b361d63213da863881504d023..eec626f27479db77feab010ade9498f98951b559 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'videosettings.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -84,7 +84,7 @@ class Ui_VideoSettingsUi(object):
 
         self.widget = QWidget(VideoSettingsUi)
         self.widget.setObjectName(u"widget")
-        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth())
@@ -151,7 +151,7 @@ class Ui_VideoSettingsUi(object):
 
         self.gridLayout_3.addWidget(self.widget, 2, 0, 1, 1)
 
-        self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
+        self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
 
         self.gridLayout_3.addItem(self.verticalSpacer, 3, 0, 1, 1)
 
index 85ec0820ea83a263cf68b5800a32e6058aa807d7..50fb8e08100fd8c679ef90d3abb526f58c1f6788 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'videosettings_mobile.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.2
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -29,7 +29,7 @@ class Ui_VideoSettingsUi(object):
         self.gridLayout_3.setObjectName(u"gridLayout_3")
         self.widget = QWidget(VideoSettingsUi)
         self.widget.setObjectName(u"widget")
-        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth())
index 4731386ad84d808d656c5b60b76caff9a77a4038..d28f2887e97dcfcd792a13edbae01a24b39aa594 100644 (file)
@@ -44,43 +44,43 @@ class MainWindow(QMainWindow):
         self.addToolBar(tool_bar)
 
         file_menu = self.menuBar().addMenu("&File")
-        icon = QIcon.fromTheme("document-open")
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentOpen)
         open_action = QAction(icon, "&Open...", self,
                               shortcut=QKeySequence.Open, triggered=self.open)
         file_menu.addAction(open_action)
         tool_bar.addAction(open_action)
-        icon = QIcon.fromTheme("application-exit")
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.ApplicationExit)
         exit_action = QAction(icon, "E&xit", self,
                               shortcut="Ctrl+Q", triggered=self.close)
         file_menu.addAction(exit_action)
 
         play_menu = self.menuBar().addMenu("&Play")
         style = self.style()
-        icon = QIcon.fromTheme("media-playback-start.png",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStart,
                                style.standardIcon(QStyle.SP_MediaPlay))
         self._play_action = tool_bar.addAction(icon, "Play")
         self._play_action.triggered.connect(self._player.play)
         play_menu.addAction(self._play_action)
 
-        icon = QIcon.fromTheme("media-skip-backward-symbolic.svg",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.MediaSkipBackward,
                                style.standardIcon(QStyle.SP_MediaSkipBackward))
         self._previous_action = tool_bar.addAction(icon, "Previous")
         self._previous_action.triggered.connect(self.previous_clicked)
         play_menu.addAction(self._previous_action)
 
-        icon = QIcon.fromTheme("media-playback-pause.png",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackPause,
                                style.standardIcon(QStyle.SP_MediaPause))
         self._pause_action = tool_bar.addAction(icon, "Pause")
         self._pause_action.triggered.connect(self._player.pause)
         play_menu.addAction(self._pause_action)
 
-        icon = QIcon.fromTheme("media-skip-forward-symbolic.svg",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.MediaSkipForward,
                                style.standardIcon(QStyle.SP_MediaSkipForward))
         self._next_action = tool_bar.addAction(icon, "Next")
         self._next_action.triggered.connect(self.next_clicked)
         play_menu.addAction(self._next_action)
 
-        icon = QIcon.fromTheme("media-playback-stop.png",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackStop,
                                style.standardIcon(QStyle.SP_MediaStop))
         self._stop_action = tool_bar.addAction(icon, "Stop")
         self._stop_action.triggered.connect(self._ensure_stopped)
@@ -99,8 +99,9 @@ class MainWindow(QMainWindow):
         self._volume_slider.valueChanged.connect(self._audio_output.setVolume)
         tool_bar.addWidget(self._volume_slider)
 
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.HelpAbout)
         about_menu = self.menuBar().addMenu("&About")
-        about_qt_act = QAction("About &Qt", self, triggered=qApp.aboutQt)  # noqa: F821
+        about_qt_act = QAction(icon, "About &Qt", self, triggered=qApp.aboutQt)  # noqa: F821
         about_menu.addAction(about_qt_act)
 
         self._video_widget = QVideoWidget()
index 3f75a0601f72d3bb3b22b64ac6b0bb1bc1b75656..c7e0c596a3a69a38a0861ab5aded16eeb4476c96 100644 (file)
@@ -34,6 +34,7 @@ class ScreenCapturePreview(QWidget):
         self._screen_label = QLabel("Select screen to capture:", self)
         self._video_widget_label = QLabel("Capture output:", self)
         self._start_stop_button = QPushButton(self)
+        self._status_label = QLabel(self)
 
         self._screen_list_model = ScreenListModel(self)
 
@@ -65,6 +66,7 @@ class ScreenCapturePreview(QWidget):
         grid_layout.addWidget(self._video_widget, 1, 1, 4, 1)
         grid_layout.addWidget(self._window_label, 2, 0)
         grid_layout.addWidget(self._window_list_view, 3, 0)
+        grid_layout.addWidget(self._status_label, 5, 0, 1, 2)
 
         grid_layout.setColumnStretch(1, 1)
         grid_layout.setRowStretch(1, 1)
@@ -86,6 +88,7 @@ class ScreenCapturePreview(QWidget):
 
     @Slot(QItemSelection)
     def on_current_screen_selection_changed(self, selection):
+        self.clear_error_string()
         indexes = selection.indexes()
         if indexes:
             self._screen_capture.setScreen(self._screen_list_model.screen(indexes[0]))
@@ -96,6 +99,7 @@ class ScreenCapturePreview(QWidget):
 
     @Slot(QItemSelection)
     def on_current_window_selection_changed(self, selection):
+        self.clear_error_string()
         indexes = selection.indexes()
         if indexes:
             window = self._window_list_model.window(indexes[0])
@@ -115,16 +119,23 @@ class ScreenCapturePreview(QWidget):
 
     @Slot(QWindowCapture.Error, str)
     def on_window_capture_error_occured(self, error, error_string):
-        QMessageBox.warning(self, "QWindowCapture: Error occurred",
-                            error_string)
+        self.set_error_string("QWindowCapture: Error occurred " + error_string)
 
     @Slot(QScreenCapture.Error, str)
     def on_screen_capture_error_occured(self, error, error_string):
-        QMessageBox.warning(self, "QScreenCapture: Error occurred",
-                            error_string)
+        self.set_error_string("QScreenCapture: Error occurred " + error_string)
+
+    def set_error_string(self, t):
+        self._status_label.setStyleSheet("background-color: rgb(255, 0, 0);")
+        self._status_label.setText(t)
+
+    def clear_error_string(self):
+        self._status_label.clear()
+        self._status_label.setStyleSheet("")
 
     @Slot()
     def on_start_stop_button_clicked(self):
+        self.clear_error_string()
         self.update_active(self._source_type, not self.is_active())
 
     def update_start_stop_button_text(self):
diff --git a/examples/pdfwidgets/pdfviewer/rc_resources.py b/examples/pdfwidgets/pdfviewer/rc_resources.py
new file mode 100644 (file)
index 0000000..7e386e9
--- /dev/null
@@ -0,0 +1,3468 @@
+# Resource object code (Python 3)
+# Created by: object code
+# Created by: The Resource Compiler for Qt version 6.4.0
+# WARNING! All changes made in this file will be lost!
+
+from PySide6 import QtCore
+
+qt_resource_data = b"\
+\x00\x001G\
+\x1f\
+\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xec}\xebs\x1b\xc7\xb1\
+\xef\xe7\xe4\xaf\xe0U\xbeDU\xc0\xb0\xdf\x0f%\xce\xa9\
+\xc4\x8eS\xa9r\xea\xa4n\x1e\xf7\xdcO.\x88\x04%\
+\x1e\xd3\xa4\x0eI\xf9\x91\xbf\xfe\xee\x02$g!h\xb1\
+\x00\x16P$_s\x5c\xf2b\xb6\xb7{\xfa7==\
+=\xb33\xb3\xbf\xfd\x8f\x1f\xbe\xbd:\xf9n~{w\
+ys\xfd\xd93,\xf0\xecd~}vs~y\xfd\
+\xea\xb3g\xff\xf8\xfb\x97\xd3xvrw?\xbb>\x9f\
+]\xdd\x5c\xcf?{v}\xf3\xec?~\xf7\xcb\xdf\xfe\
+\xaf\xe9\xf4\xe4O\xf3\xeb\xf9\xed\xec\xfe\xe6\xf6\xc5\xc9\xef\
+\xcfo^\xceO\xfe|u\xf5\xf6\xee~\x91u\x82T\
+\xa0\xc0\xe4\xe4o\xff\xfc\xd3\xc9\x1f\x7fxss{\x7f\
+\xf2\xd7\xab\xb7\xaf\xa6\x7f\xbe>)\x8b\xcc\x7f.e\xbe\
+8\xb1\x02p\xf2\x87\xb7\x97W\xe7'\x8a\x22\xf1\xfc\xe4\
+d:mD\xdc}\xf7\xea\x97'''M\xf9\xae\xef\
+^\x5c\xdf}\xf6\xec\xf5\xfd\xfd\x9b\x17\xa7\xa7\xd7we\
+\xd6\x8a+g7\xdf\x9e\xfem\xf6\xdd\xfc\xcb\x9b\xdb\xff\
+3\x7fy\x8a\x05N\x9f\xd5'f\xef\x7f`Q\xd2F\
+\xfe?/\xe7\xdf\xcfo\xff\xf8\xc3\xfd\xfc\xba-\xc6\xdd\
+)\xaf>~\xb9\xe1\xf1\x8e\x9e\xa7\x08\xab\xcf\x9d\x9f=\
+=\xf8\xe6\xed\xedU\xb9\xb9}uz~v:\xbf\x9a\
+\x7f;\xbf\xbe\xbfkJ\x89]\xf2\xb3J~v;\x9f\
+\xdd_~7o\xc4|\xdb\x14\xa8}\xb2\x91\xfd\xab\x0e\
+\xf1\xed\xf9\xc5\x13\xf5\xf7\xdf\x7f_\xbe\xe7\x05\x11f\xe6\
+)\xd0)\xd1\xb4\xa1\x98\xde\xfdx}?\xfba\xba\xfa\
+h\x03\xe6\xfb\x1e%\x008m\xeeU\xca\xed\xa8^\xfc\
+puy\xfdMoa\x16w\xbb\xd2\x1b{zss\
+^1}\xcc(w7oo\xcf\xe6\x17\xcd\x93\xf3r\
+=\xbf?\xfd\xe2\xef_<\xdd\x9cB9\xbf?\xef\xb0\
+i\x98\xde\x9d\xcd\xde\xccW\xe4>f.\xf1\x9a};\
+\xbf{3;\x9b\xdf\x9d>\xe6\xb7\xcfw\x0d\x1c\x17\x19\
+\x97\xe7\x9f=\xfbj\xf6\xe3\xfc\xf6\xeb\xe5\xef\xef/\xcf\
+\xef_7\xb7)\x16?_\xcf/_\xbd\xbe\xaf\xbf\xbf\
+k\xac\xe5\x0f7?|\xf6\x0cN\xe0\x04)N\x1eo\
+\xdc4\x9c/\xaen\xbe\xff\xec\xd9w\x97w\x97/\xaf\
+\x96\xe2\xe6\xd7\xb3\xe6r\xfarv\xf6\xcd\xab\xdb\x9b\xb7\
+\xd7\x8d\xb0\xeb\xf9\xf7'\x9d\x87\x1f\xb5z\xd1\x96\xb6Q\
+\xe8\xcd\xed\xfcn~\xfb\xdd\xf2\xf1G\x00^<\x15\x1b\
+\x0a\xd3\xe2\xd6\xa3V\xdd[b\xabO\x9d\xdf\x9c58\
+4L_\xddL\xaf\xe7?\xdcO\xdf\xcc\x1at\x9b\xfa\
+\xfb\xd7\x1a\xdd\xcb\xd9]Cw\xfa\x8f\xbb\x86\xdb\xe9\xf9\
+\xec\xbb\xcb\xf3\xd3/\xe6w\xdf\xdc\xdf\xbc9\xbdk\xda\
+\xfc\xcb\x9b\x1fV\xa5\xde\xbc\xbd\x7f\xf3\xf6\xfe\xeby\xdb\
+l\x96\xe2\x1b\xd4k\x15,o/D=e\xae2\x98\
+/\x5c\xc1\xf4\xe2\xf2j\xbe,\xe3\xe9\xeb\x9bo\xe7\xa7\
+o.\xaf\x1b\xc8oo\x9a\x8b\xb3\xbb\xd3\x9b\x1f~|\
+5\xbf>m\x9e\xb8jq<\x9d\x9d\xdd/\x9a\xe8\x8a\
+>o\xae_\xbd\x97\xf5\x0f\xe7o\x1a;3/\xfa\xde\
+\xdb?\xd6\xdb\xbf\xfb\xed\xf9\xfc\xe2\xee\xd1\x1a\xdak\x84\
+6\xf7\xe9\x917\x0d*o\xe6gm\xa3\x5c\x01\xee\xfe\
+\xc7\xd6\x06W\xc9\xf8\xfc\x9d\xfay\xf3uc.S\x85\
+\x93\xc6\xc3A\xfb/\xae\x11\xfc\xd8\xd4^{\x03\x16\xf7\
+a\xed\xfe\xbf>{\xe6\xb0\xce`U\xec\xf4\xe6\xf6\xf2\
+\xd5eS\x13\xbc \x92J\xbaP\xab\xa3\x03!=;\
+9\xfd\xe9\xea\x87\xa6\x0b\xfd\xbe\x9d\xdd~3\xbf]\xe1\
+uw\x7fs\xf6MK\xfe\xfb\xdb\xdb\x9b\xef\xf1/\xf3\
+\xeb\xa5:\x0d\xef\xf9u\xd3\xcego\xefo\x16\x19\xb7\
+\xf3\x8b\xff\xdb\xb6)x\xfc\xf5_\xf5\xd7{\x9e\xbf\xbb\
+\xff\xf1\xaa\x81\xea\xd1\x0b\xbcxp\x02\xbfi\xac\xe8\xcd\
+\xec\xfeuK\xb2|\xae\xfd\xc5\xac\xfel\x99\xd5\xe4\xfc\
+\xe5\xa4\xed\x1f\xa1\xc0\xc9W'\xda\x5cMuq9E\
+*\xda\xc9^\xe4>\x91\xfe\xeb\xa4eP\x057\xed\xe8\
+jz\xfb\xf6\xaa1\xef\xef\xe6\xd77\xe7\xe7\xbfi\xfa\
+\xa5\x9bo\xe6/~\x05\x8b\xbf\x87\x9f\xd3\x85{{\x81\
+\x05\xde\xdc\xfff\x09\xcf\xb4\xe9\xd4o\xef_\x5c7\x9d\
+\xfao\x1ex6=\xda\xf5]\xe3\x8a\xbf\xfd\xecY\xdb\
+\xf4\xe6\xbf\x86\x22\xcfOno\xeeg\xf7\xf3_c\xc0\
+\xf3%\xc5\xd5\xe2'L\xe0\xf9\x02\xed\xd3%\xbf\xad`\
+_\xc8\x1c\x01|\xe5\xd0\x0b}\x1f\xf2\xf21\x22\xbf\x01\
+\xf8\xd1`\xffm4\xd8\x7f\xdb\x17l\x83O\x0bl\xea\
+\x82m{`\xfd\xd5H\x7f\xf2\xd5\xbe\xfe\x04?1\x7f\
+\x12\xbd\xfe\x84\x8a\xee\x03\xfch#\xffj_#\x97\xf8\
+\xb4\x8c<\x06\xe0>h\x5c\xb0\xe8\xd4e\xdf\xa0\x00)\
+\xea\xf3\x1bc\x82\x05\x8dP\xb1\xf6\xcf{\x03\x83\xf0\x85\
+\xa6\xcd\xa8d>\xbb\xfd\xd3\xed\xec\xbc5\x95\x15\xc6g\
+7WW\x0dqc>W\xdf\xcf~\xbc{\xe2\xb2\xfa\
+\x88!rc\x0e\x8d\x11\xbeY\xa9\xba6c\xda\xb0\xb8\
+\xb9\xad\x95\xd5f\xdd4\xc1\xfd\xe5\xfd\x8f/\xf0\xb1I\
+\xdc\x5c\x5c\xdc\xcd\x1b)\xf0\xac\x9aSKi\x88m\xec\
+\xb2\x07kx\x975\xae\xb3\xf6e=\xaf\xea\xf2\xbb\xdf\
+\xb6\x17\xb3\xab\xad\xe1X\x0c\xea^\xbc\xbe\x9d7\x83\xd0\
+_\xad\xf2b\x02\x7f\x82l\x95-Q\xe8\xe2\xd6\xab\x87\
+\x8c\x7f\x5c_\xde7\xa3\xcc\xb7\xcd\x90\xe3o\xed\xd8\xe7\
+?\xaf\x9b\xd1\xc7\x0a\xc5\xdf\xab\xf1~;\xbb\xbf\xbd\xfc\
+\xe1\xd7X@\x88T&\xd0\xa6\x82d\x802!,\x9a\
+\xed\xc54\xa8\x18z\xe2\xf3\x05\x9f\xb3\xc6\x00%\x0b \
+\xa6\xe32\xa71:*\xe6\xc2\xe0\xb1\xc8\xb9X\xa3\xb9\
+X\xa3\xb9m\x87\x8bNb\x98\xdcc?\xeb&B\xc4\
+4d\x22/%\x85f;\x9a\x08\x11\xcb\xb0\x89\xcc\xe5\
+\xfc\xec,\xdfa=`!Dl\xef\xb7\x90\xfa{\x84\
+\x85TX\xfa\x10\x0b\x1em!P<\x125\x17\x16\xf2\
+\xf4\x83\xb0\x80\x85\xca\x84\x8b\xa4\x13\xc5|J\xcf\x97E\
+\xc5E\xfd\xa32,\x85\xff\xd8d\xb8\x16F`\x8c%\
+\x09}\xf6,\xa8H\x88\x09-i\xa8C\xb3\xb5E0\
+\xb1>\xdb\x88]\xad\xd3Z)L\xeck\x16\xd1[\xed\
+\x17\x8b\xbf5\x8b:9\xeda\x9dk&\xb1\x13k\xf8\
+\xcd\xf1\xec\xa5\x82\xd6o/x\x00\x8f\x82H\xc29\xc1\
+\x02\xac\xc26\x99\xb6Wh\xc6\x93\xf6\x9e)\xf8\xc4\xb4\
+\xa8\x83\xf2d*YP\x08\xa5c<Q$C\x8d\x9e\
+\xac\x07J *H\xda\x93\xf9H\x14gr\xe2'\xf3\
+\xa1\xc2\xa6N\x96;\x98\x0fx\xb5\x90\x81:\xda\xc5\xa1\
+0A\x0e;\x14\xd26\xed\xd8\xe70!\xfe[\xfb\x1c\
+\xcf\x03X\x88bz\xedsBRh\x82R\x02\x12\x1a\
+\x93p/\x88\xea\x1fC\x9f\xc3Dz$\x13!\x1f6\
+\x91\xd9\xbcM\x03\xacq\x9du\x1e\xdfDH\xfbM\xc4\
+\x8f\xe1D\xa0p\x84yL\xa0\x08\x81\x89L\x0c\x0aB\
+\xd0d*\x5c\x88Am\xd5` #\xe4\xc9`\xa2H\
+*#Q5\x18/\xec\x10\x11O\x06c\xc5\x1d\xd0\xd2\
+\x1f\x0d\x86K\xba\x82\x80no0L\xfa\xfe^\x87\xe9\
+h\xbd\x0e\xd3\x11{\x9da\x8d\x81\xf7i\x22P,X\
+\x94\xc9\x06\xdb\x0a/*`\x0f\x19\xc3\xee\x94\xe1\xf8!\
+<\x03\xf7\xb7\x95C\x04h\x99\x99m\xb0\xee%\x04M\
+l>\xe5\x89\x163\x03\xcf\xf9T&T@\x82\xa1\xc9\
+\xa7\xb63&!bi\x89\xbch \xab\xd7\x86\xc3R\
+\xcc\xdd8\x9f\x1a\x8e\x171\x22\xb7e\xce\xc5\x1a\xcd\xc5\
+\x1a\xcd\xed\xa2mi*f\x0b\xeeA\x83\x17\xd0\xe8\x0d\
+^\x1c\x0f\x80e\xa8)P\x1b\xe8f\xea\xd2\xefx\x9a\
+Q\x9b\x15\x9a\xc62A\xd4\xa2H<\x99\x12\x96d\xf1\
+\xac\xc1\x0bba2\x0ey\x0a^\xd4\x0b\x07g\xe6S\
+\xec\x82R$Y\x19\x974Tiv\x88]@\xe3\xfd\
+~\x06\x0c\xb6\xf739s[\x1fRo1\x18\xe2\xd9\
+\xf9\xf0P\xbc@R\x12\xb0=[+\xa3\xf5\xf92p\
+Xc\xa3 \x8c\xbe\xd1\xa7\x9d\x9d\xd3\xd9\xb6\xee\x12,\
+\xd6D$\xaa#\x87>\x1bPy{\x19\xb4\xbdK~\
+\x99\xd1\xc3\xfa\xa8~\x094z\xfd\x92\x8d\x0f\xf3\xb4\x90\
+9\x0b\xb6^G\x0b(\x1a\xca\x83\x07\x02uOY\x0e\
+\x07\x88\x9b\x8b\xe0\xe2\xae8\x99\x9a\x15\xe5\xd0\xe8x$\
++\xe6j\x12O\x1e)\xb5\xb8%y\xf5Hh\x85\xd0\
+Y\xa5v\xe5RP\x90\x02;\x1e\xc9\xc5\x04v\x98o\
+\xd0|\x7f\x13#\x83\x1d\x9aX\x0d\xf3\x87\x9b\xd8\xf0s\
+\xebm\xe3\xd9Z\xe1\xfa\xda\x16\x19\xac\x1b\xbe\xeb\xb8\xa2\
+w\xb9\xef`\xf2\x00\x00\x1f\xde\xe4Is\x83\xc9\x1f\x22\
+lU\x09\xe5\x09\x16\xb1D\x94E\x0f\x01\x8a\x16\x13\xa2\
+b\xa1\x19\x13$\xa7\x92\xd2\x0e\x8b)\xb1\x08P\xb5u\
+\xd4\xe2\xe4\xe0\xfed\xeb\x1a\x05\x22-\xbc\xda\xfa\x0a\xcd\
+\xc5\x1a\xcd\xedb\xe0\x83\xc2i\xba\xc3\xdc\x9a\xfa\x91\xe6\
+\xd64\x8f5\xb7fxt{!\xf5~{9\xc4\xec\
++1\x1a\xda\x04\x0b%\x0aac\x14X\x1c\x16YX\
+\xd0\xa3u\x8e\x82X\xc2\xa5\xb9\xc7\xa4E\xb5c0B\
+\xc5\xd0\x95\xeb\xc0\x18\x09\x8a\x09>\x8ej\xd6h.\xba\
+4u\x9c#`\x11\xbb\xcc\xbc%\x0e\xd8\xcb\xcb\xabf\
+\x8d\xceZ\x95\x0e\x0c\x8a\x17C\xf3\x9d\xf9\xc2\xe0\x888\
+u\xdb\x01N\x1b\x8e\xc1S\xa8F\xd1\x8d\xe3\xf4)\xcc\
+\xa3\xd8\xb2\xee\xd7\xa1\xc30k\xfa\x95_\xfe\xe2\x17\xbf\
+x\xd0\xb3\x16\x14\xc3\xda\xf0\xa7w\x80sv\xf6\xdey\
+\x86\x0ah\xa3e?g\xea\xe1\xfc\xfd\xeb\xcb\xfb\xf9\xfa\
+\xc0\xa9\x0b\xe8\x03\xdf\x8f\x03@M\xf3>\x005-\x07\
+\xd4\xdc\x0b>M\xc7#\xc3W\xdb\xda\x7f\xfd\xe5\xab?\
+\x7f\xf15}\xbd\x1dD\x15\xcf\x8as\x17\xffZ)U\
+\xb7n\xe9z\x0d\xee\xcb/\xff\xf8{\x80g+8\xd0\
+\x1aDU\xc9^6\x9f\x7f\xfe.\x1b\x19@d?\xe7\
+\xbd\xc4-\xbf\xee\x1b!r\xe2\x0e\x90\xa6\x14\x16\xae\xb8\
+\x22Pa\x11\xaf\xaf0\xac(\xab=\x01\x9cR\x94\x1f\
+F6\xe3\xd5@\xd8\xa0\x07\xef\xa2\x87vT\xe0\x95\xd2\
+\x87\xe9J\xe9\xc3\xf4P\xa5\xc7\x0d\xa5\xd7\x03\x94\xde\x0b\
+%\xd7\xc2k\xfb\xf3Pe\xa7\x0de\xf7]\xcan\x9d\
+\xb2K-{\x14\x00\xa0Zx[\xfe>9\xad\xb1\xcb\
+\xfe\xa5\xf7\xaf\xfb\x22\x16\xd9&b\xa9\xb1(P\x0d*\
+\x90\x0a\x83<\x05\x98\xc8YTC\x0fT\xe4\xd8Pd\
+?p\x91s\xe9y~\xdb\xc4a\xcdJ\xe4\xeb\xff|\
+\xf9\xdfM\x01\x174\xf3\xffy{y;?\xaf\x0b\xd7\
+w_\xa7\xfe\xe8L\x1b\xf9\xb0\xb2\xf8yu\xe9\xf3\x93\
+\xb6+\x85X\xf6i\xbf\xbd|\xf1\xe6\xd5\xc5\xff\x9e_\
+\xaca\xb5(\xc2\xd7\x97U\xf2\xd7\x0d\xe1\xf2\x99\xd3\xc7\
+\x87Z\xcdNW\xb869\xbf<\xa6SEb\x87O\
+\xdb\xabVE\xe8St\xab\xb5\xf8\xf2\xe9\xf9\xd5Zx\
+;\xaec\x1d_\xfc\x8d\xa5\x8f\x03\xc7j\x07\x9e7'\
+\x86\xec+\xbd`\xec\xd2\x80\xa7.%\x08\x1c\xbcS\x07\
+P\x82\xd8\xeb\xea\x8e)FA\xc2\xac\x0d\xa1\x12}X\
+\xd5\xf2\xd3T\xad\x8et\xfaGA\xce\xbb\x18\x9d\x17\xc7\
+t\xa9-\xc7K\x04\xd6\xe6\xb3F\xd2\xe40\x14\x11\xc4\
+\xd0\xbey\x8c\xce\xba\xc7\x22\x0e\x826\x9f\xb6\xcb\x1f?\
+`\x1dk\xba\x7f\xd0:\xae1\xcf\xe1\xebx\x95/j\
+\x86=E7d%U\xba1\x0ec\x01Q\xd0e)\
+/\xd6h.\xd6h\x9a@(JZ\xa0\xf2\xf0\xb2/\
+\x95\xf4\x98L\xa9\xa4&\xc7b\x1e\x1f&P\x12\xd4\x9d\
+&^L\x81\x5c'\x08%<\xc0\x9f\x0f\xd7\xc2\xd1=\
+q\x98\xfa\x11<q\x1bc\xadJ\xea\x95/\xf9\x11\x8e\
+\xda\xc3\x14G\x0e\xdc+'\xee\x19\xbb\xb7yM\xf8y\
+@\xf7\x17f\xd1_\xd3.\xbb4{\xce\xa2\x8cT\xa3\
+\x9e\xda\xdc\xeb\xcd\xfaB\x16\x0b\x86\xeb\xf1\xed\xd5E\x8e\
+`\xaf\x1f\xac\x12\x5c\xec\xd8\x95p\xf4A\xa6i\xc8!\
+\x16ax8\xf1\xe3\xa2\xb6\x0cl\x12M\xb2\xb0\xa1\x03\
+\xe1\x04\x0b\x1a7I\x9e\xef6^=\xf6\xb4\x80i\xf8\
+\xfe\xea\xd7\x00 \x9an\x7f\xe4\xe4\xc1xC\xed\xd11\
+\x95\xa0\xbeP\x86\x02\x08\xc8Y\xfbQ)\xae\x80R_\
+(\xaf\xd2\x5c\xac\xd14j\x10\x14\x0f$\x1dz\xc5\xb3\
+0\x08,\x94h\x08\xadyLQ\x8bzrl\xd1a\
+\x1e}N\x88>\xcd\xca\x1f\x9e9\xa2\xc8\x8f\xbbQ\x1f\
+w\xaa\x9b~\x22S\xdd\xf4IOu\xd3'<\xd5M\
+G\x9c\xea>~\xebw:Z\xeb\x9fb\x14\xe3\xa0\xb4\
+\xc9\xd4J\xb0\xb5\xe9#\xeb\xd4\x89\x5c\x0f\xe1\xd7\xa7\x98\
+%\xdb\xbf\x98Lc\x0f\x0f\xdf\xec\xbc\xbc\x9f\xdfn\xb5\
+\x1fpI\xca$\xf8\xacyn\xfe\xa7\xd9\xdb\xbb\xbb\xcb\
+\xd9\xf5\x1f\xae\xde\xb6\xcf\x0fqh\x070\xe7_\xcc\xbf\
+\xbb\x9c\xdd?\x1e\xb7\xc3)\x8a\xd2Y\x0a\xb0\xca\x94I\
+x\xb9(`)\xf9\xa8\xf5! v\x88\xfa\xa0\x22\xd0\
+\xfe\xe1|j\xbbv\xb9\x07\x1e\x18\x18\x22\xf7o\xe6\xcc\
+:f\xe1\x22\xe1Fu3\x98x\x81\x8c\xf0\xda\xbd`\
+1\xf5\xb4\xac\x1d\x0ceAb%\xdbkRa\x10G\
+\xe3\x92\x92\x16-\x88O2\xa7X\x04\xc4M\xa2\xfa\xaf\
+B\x1c\x86\x91O\x85\x9f\x22\x970\xc9\xa4G\x0d+\xd1\
+\xdeK\x1a\x982\x86\xb7\x5cDl\xde\xec\xb6\x8eC\x9d\
+\xbc\xf2\x92*Y;\x15\xe7\x22F\x16\x9d.\xc7K\xfb\
+\x1b\xa3\xea\x05\x85\xc5\x1c\x87\xd7L33?\xf9\xc9h\
+\xff\x12'\x98\xc5\xc5\xc3x\xc2X C\xd9\x9f\xef\x8d\
+\x10\x11\xf8 BL\xbc?BYB\x12\xac\x8e\xa9\xa1\
+3J-h\x0a\xd01j\x18\x02e\xc2\x85\x1f`\xa1\
+\xa2\x9a\xbc\xd8\xa9\x02\xc58\x83|2E\xcbB\x8c\x8e\
+\x13\xcbb\x0a\x969\x0a\x1d\x19F\x07e_tH\x8b\
+\x87\xa1U\xfb\xe1,d\x81\xd5~*Mg-<\x17\
+T'\x1e\xf6k\x88%\x17\x7f\x13\xd8\x1f\x05V\xe5\xe1\
+\x99\xe4\xcc\x8f\xc5F\xaa\x85@\xb5\x8cj-\x0b\xc3\xe0\
+@\xb4\x07k\xc1D\x1e\x85\x0e\x8e\xb0\x91\x8f\xcb\xc7$\
+\x1a\x89\xc6D\xa0X\xfb\xa7\x13\xa6\x02\x16\x064\x06!\
+\xc9c\xfa\x18\xa6\x0a\x8d\x14f`\xa2\xda\xafh\x09\x06\
+B\xb2\xda~\x80\x0a#\x92\x0c\xaf:v\x14\x0a[\x80\
+C\x8b\x0d\x94\xa2\xca\xea\x93)\xc9(<|\x0b\x8b\x81\
+\xbd\xbd\x8a/\x1b}\x85\x05I\x0a$j\x85%sA\
+\x13Z\xb7\x07Sq\x0ac\xd9\xab[\x9aLu\xd9\xea\
+\x96\xadj\x99k\xa30\xd2A\x9f#\x8c\xfbb\xa4\x92\
+\x05\x0cY:\x9e7\x8b\xbbXg\xc0\x85&\xc5,\xab\
+\xe5T\x9a\xcd\x18eq4\xd5\xc8\xf9\x94\x1e`B\x06\
+\xc4\xe4vh\xc3`h\xe9\x8d=aQ`\xe5q8\
+\x0d\xfaf\x17\xa2]q:t\xcfr\xa0\x1e\xaf\x17\x05\
+\x941=\xd4O\xdf\x07\x93\xb2\x8c\xf0\xc1?\xf1>\x9c\
+\x94\xc7\xf7\xe1\xbb\xece\xe6\xbe\xbd\xcc\xba\xfd\x06\xa83\
+?;?\xf7m7\xce\x89\xc6\xb8\xbd\xcc8\xfe\x04\x8d\
+>8P\x8es\x16\x00\xa3\x1dm\x7f3\xc6\xf1\xe0\x80\
+c\xc1A\xc7\x83C\xf6\xdf\xe9\xeeB\xf4\xde\xf6\xe0B\
+\xb2}{x)M\xb2\xdd7\x04\xe6Y\x9e\xcdp\xe7\
+\x0d\x81\xca\x12\xc3\xcc\xcf\xce\x9bF\x8a;\x9e4\xe1B\
+\xb6?\x9c$\x8c\xef\x85\x93\x84\xf90G%\x8c\xb7\xcd\
+\x22\xa4\xe9\xe0\xf9l\xad\x8c\xba\x85\x0cl\xd3p\x95E\
+\x92\x07\xae\x8b\xf0\xbe\xbd\x96\xc2\xb9\xc6%\x800=6\
+\xb8\xcb\xf9\xacM\xdb\xee\xe7\x14\xc1\xed=\xf1\xf9E\x93\
+\xd6\xd0\x1ca\x1c\x9c9\xe4] -\xe6\xbbz\x17\x12\
+\xc0m\x0e^9kv[\xed\xd8\x1cH\x80\xc7;\xdb\
+\xe1\x18\xb9\xcf!\x8fx\x97;rD\xf0\x03n1.\
+\xa1.\xcd\xda\xf8\xe6\xd0+\x06\x85\xb1\x1f\xa7\x1c\xc6\xe9\
+\x90\xa3\xcb\xf5\xb1\xeb\xfa\xf8\xb6o\x0c\xdc\x1d'\x1f\x18\
+#f\x84^\x8c\x92\x861\x1a;/\xb1>\xcf\xb1>\
+\x19\xb2>cR\xa7Sv\xd8\xae\x1a\xb1\xcfAq\xb9\
+\xc3>\x7f\xc3\xb88\xa7\xad\x0f\x8a\xcb\x1d6\xcb\xcf\xe4\
+\x0c\xe6\xf2\x0e\xeb\xf7y\x9a\x9e\x93F\xd7\xcf\xedd!\
+\xdd\xe1L\xf0\xa1\xf3\xc5\x87\xcf\x22\x1d>\xe1|\xf88\
+\xd4\x83/*\xce\xec3\x7f\x07\x19m\xfe\xd3\x87\xa5?\
+\x13$\x99\xac\x98;\x14\xa0\xd0\xac\x13\x09P\x10\x03\xba\
+\x93<Q\xc0X\xc1\x1f\xad\xbd\xd2\xec\xf9^\xd5\x9d\x0e\
+\xf1^\x15\x8a\x02\x18\x93lx\xb1\xea.\x1f\xec\xc5*\
+\x19\xc8A\x160\x15h\xffh\x22\x1f\xd9:&\x03;\
+\xf6:&\x9d\xe8\xc7\xba\x8c\xc9 ~\x12\xcb\x98\x0c\xe1\
+\x13^\xc6dH\x9f\xec2&C\xf9\xd0\x1b\xcbZ\x0a\
+\xb3B$\xa2\xd5\xf6\x94\x0aa\x88U\xf34.\xc8\xa1\
+\xa8\xb5kH+b!6\xec\xb0\x90\xa3x\xb8\xc4d\
+\x0aK6\x9e#\xa6\xe7Ilx\x01\x82\xc1\xfe\xd3\xae\
+V\x84\x5c\xad\x86\xb9h\xc51\xc4k\xd0\x07\x85\x0d%\
+H\xadNM\xfb\x12\x8f\xf87\x00\x22\xc7\x04$t\x81\
+\x87\xe6\x13 \x92\x0b\xfbp\xaa\x16h\x0fz\xd4\xf1\x83\
+\x97\xb4\x96f;8t\x02\xa3\x10\xa0a\x04\x80\xf6E\
+\xc0\xb4\x88\x04\x22U\x93p.\x19\xe0X\x11 .\xae\
+aR[\x88gA'\x921z\xc1\xb0^\xa9\xff&\
+\xbd\x86k6}\x5c\xb5r\x8cV\xbf'\xeaiB\x03\
+\xb5z(\xa4\xd53\xab\xbc\x06\x13n5\xc6p\xdar\
+\xf5<rpR.V\xcfCQ\xf4P\xdf\x05\x83\xd5\
+\xb22\xb1\xf5u%\xf2\xf5x\xcd\x91\xb0\x88\x10r\x05\
+ \xa2D\xa0\xf3G\x06\xc3\xa0\x8f33\xdb\xfb\xdd\xb5\
+\x17\xf2$\xae-\x81\xc8\x8au\x06>\xca\xc5CP\xb9\
+\xbep#.L\xfe\xd0z\xee\xde\xdc\xceg\xe7\x7f\x99\
+\xdf\xbf\xbeiK?\xbfh%o\x85\x15\x940\x041\
+n\x91\x8a\x82\x86\x1c\xcde\x116\x0c\xf3Q\xed\x87\x8e\
+\xdaSZq\x05\xeft\x0c\x1e%9\x99+l(\x85\
+\x5c#\xaa\xfbp)\xae\xfd\x90\x8d\xd0\x96\xf2\x88\xde\xc2\
+\xa0\x1e\xd8h\x85E\x14\xea^V\xa7\x02\x04\x81\xb5\xcd\
+\xac\xd2\x9cui\x86\xc6\xe2P4\xd0(t\x82\xc5\xcd\
+\xdd\xbc\x9d\xe0\xa4b\x19F\x92\xed\x0f(\x11\x1e\x19M\
+6k\x01\x0f\xb4\x89\x96\x14LH\x19\xd3\xca\xc8\x07!\
+\x14\xc9\x9f[Y7l\x0f\xb2\x91\xc1\xc7\xf8V\xa6\x85\
+\xd9T:\xad\x8c\x8b\x0b\x19\xc7qZ\x1ao\xe3W\xc6\
+\xb7\xb4\xb0\x12di\xb5\xa5M\xd1\x8aYH\xd43V\
+W\x89\xceV\x88\x86\xdb\x1ai\x98\x81\xb7\x91\xb8\x12\x92\
+\xb8\xb4\x97A.,2\x81\x22\x08\x06\x88\x13\x06*\xca\
+):Q(\xa0\xaa\xa9\xa3\x1a\x1a\x1e\xb5\xa1\x15TM\
+\x8dN`\x07RHW\xa2\xba\x04\x0b\xee\x8c\xe7\xa4\xe8\
+\x10\x5c\xef6%v=PO\x85\x83\xbe\xdb\x04\x0e\xb4\
+X\x842\x07\x97\x03\x9c{\x9bv}a\x97I\x07z\
+\x9b\x8b\xeb\xacG,\x07`b\x1f\xd4X\xe7\xb6\xf3\x02\
+\x08\x0a<\xday\xf7$\xb8\xbf\xc6f.C\x1a\x03\xa0\
+I\xec\xa8\xb1\x99\xdb\xb0\xc6\x88\xb3\xdcYc3\x8f1\
+\x1a\x9bU\x8dW\xd8Z\xecp\xcc\xfa\xc5\x19^\xd0\xee\
+k\x144|\xfer\xf73\xa0\x19\x83+\xf3w\xe1\x80\
+\x1dNi>\xa3\x99\xaeU\xe6\x188e\x9boE\x9c\
+\x9f\x9f\xedl@\xb2U\x939\xbfx\xb9\xbb\x01\x89\x8f\
+\xd1\x98qHc\x07v\x80\x9d5f\x1e\xd6\xf8\xe5\x85\
+\xce\x01v\xd6\x98u\x84\xc6\x22v\x94ua&\x12G\
+r\x8b&\x0ac4\x86a\xb7\x188\xe7\xf9\xce\x1a\x83\
+\x0dk\xcc\xe1\xe7ko\x87\x875\x868\xf6\xe9\xd9f\
+f}\x072\xd8A\xd6\x17p\x9a\x92\xf2\xc4J\x06\xa3\
+(\xb6\x1f5\x99z\xf1@Ik\x7f`Q5\x0cn\
+C*\xa2\x12d\x88\x93\xa9e\xb1\x0cC{\xfe\x9eH\
+\xfe\xcd\xec\xbc{\xbe\xb6\x03\xb0v\xde\x85\x01\x17\x0d\xa8\
+S;\xab$\x17\xef\x92\xdc.(TSb\xc4{\xa6\
+\xfe\xe0\xad\xcf$\x11\xea\xca\x9c:\xa5\x1cQG\x89R\
+7>n3\x9dz\xf0\xc2\x8b\xf5\x16^\xa9\x0eU\xb1\
+@J\xe6Ci\x979\x08\x98)5\x0e\xd7\x82\x91\xc8\
+\xdc]2\x03\xe0\xa1\xdb\xe8\xd5?\x96\x1b\xde\x1e\xedE\
+\xc3!-Z\xab\xe3\x00\x13\xa5\xe7\x1f\x12);\xc8\xdb\
+o(\x82\x94\xc04\x81b\x98\xac\x12\xcf\xfbq\xd9\xb9\
+n\xc8\x22b\xa5n\x1c \xf3C\xe2\xe4\xf0\xb1\xe3\xc4\
+%\x0dA*LQ\x885\xc5?(L\xf43L\x9d\
+\xc0\xad7\xa6\xab\xaf\xe4T\x0b\xb7\xba\xd6\xed\xed\xf5\xd5\
+\xcf\xda\xdd\xe5:\xb6DF\xf1\x0f\xefqM\xb8W#\
+\xa9{^\x8c\x0ap8Rw&,\x91\x1d\x1f\xd4Z\
+#i\x15\x85\xe2\x14\x19z\x10\xfb\x99\xf0\xc1\x9d\xa8\xb9\
+\xf4*\x1f\xd0\x99\xb1)\x90\xe6\xaeu\xf6\x14\x8a\x06\x98\
+x\xb5\xc1,\xc9\xc2\x5c\xd7\x91D\x14c\x96\xf8\xa8\xba\
+Q\x0a\xdc\xe5p6\xeb,\xbf$+\xc9f\xab\xcb/\
+E\xdc\x8d\xaa\xceT\x802T>\x9cFL\x8c\x87\xf1\
+Od\xc4F9\xc1\xba,O\xb3\x10i\x80w\x0fH\
+Mg\xc2Z\xf3\x95\xe6\x11\x05\xb1B\x14\xa1\xf9AQ\
+\xe0\x03\xa1\xc0L\xd4\xa2P\x12\x15R:h jq\
+3\x8f\x8a\x06\x16\x08I\xa8\x11$c\xe1\x0e\x0d-=\
+8#\xe9\x81\xc1`b\xef\x05C\xb8\x9e/hPR\
+\x94\x14\xab\xeb\x02-\xc1\xa0\xb5\x07i\x88\xaa\x0d\x0f\xe3\
+\xf8\xe1\xfc\x10y\xc0.\xed\x15\x8a\x00\x81UOeR\
+\xc0\x0d\xa5\xbe\xd4\xa845\xd4\x87\x92F\x84r\xe0\xe3\
+\xf7(\x13zO\xf1\x87<\xc0j\xda\x82 \x10\xa1\x13\
+(A\x01f\x8b\xf7\x0bf\xe2\x92\xd6^F\x183\xf9\
+\x04\x13\x8b\x88\x11O\x8c\x0a)'\xd8P\xf8\xd1\x8e\xf5\
+\x8c\x0b\x08\xbak}G/%=\x05\xa2\xbe\x93\xe4\xa2\
+\x8a\x84\xf5]\xbfb\xd1\xa4\xcc\xfa\xa19.\xe2\xe2F\
+\x0b\x80\xcf\xae.\xdf\xfcuv\xff\xba\xbd\xf9x\xbdy\
+\x12\xff\x91\x8a\x91\xda\x1d0o\x9a\xcb\xee\xd0\xbf]\xcf\
+{\xf5\xe2\xed\xed\xd5\xaf\x7f\xb5\x8a2#\xf3\xf3\xdf\xb4\
+w;\xb3\x00w\xf7\xb77\xdf\xcc_\x5c\xdf\x5c\xcf\x1f\
+\xae\xa7\x8bO\x12\xbc@+\x92\x0a\x00!\x8f7\xda\xfa\
+lj\xfe\xc5\xed\xcd\xdb\xeb\xf3n\xe6\x7f\xdf\x5c^\xaf\
+\xe6~{\xd9\xac\xeb\xbd\xbal\xfe\xf7\xe2\xe9\xf1\xf3\xd9\
+\xdd\xeb\xd9\xed\xed\xec\xc7\x07i5w9\x07\xf1B\x0a\
+\xeaC\xf6\xda\x17\xa1\x1a\xbd\xffr2\xc5\x90\xe2l\xa2\
+\x13\xf2\x92\xc2\xae'\x9f7\xb9)%]\xdd\x9er\xf1\
+dJ\xa0\x85@\xcd'\x8c%0\xd0\xad\xc9D*\xe9\
+@6\xe1,\x1a\xe4F-\x03\x22(\xe9.1\x11/\
+\x1a\x99\xc9m\xa6\x94\xd0\xd4\x89F!\x22\xc3\x87<\x83\
+$\x9fX\x14\xf7\x14\xc8\x93\xaf\xba\xd9i%\x88@\xb0\
+e[\xb3\x11\xa0\x84\xb3G\x9b\x89\x85U\xbc\xcd\x94\x82\
+\x14\xd4f\xa2\x17\x86&\xd5\xcc\x96/*\x15\xb4\x8c.\
+m\xab\xafDA\x0c\xe4.\x0b\x14)al\x5c\x85u\
+3k\xc1\xbe\xeafW5>_f\x1b\xb2<iL\
+KY\x92*\xd8\x85\x06\xd5\x8a\x02\x99\xac\xc2\x88&\x85\
+\xcc\x89\x9e \xc7&\xd3\xa5H:\xf2c\xe5H\xbe\xb7\
+\x1e\xffu\xb2R\xbf\xc2E\x02\x01e\xc1\xd8\xa3p:\
+\xe4S\xb6\xb6\x99T@\x02}\x22Z\x12\xbdek^\
+\xd0#p\xa2P<\x9c\xd4\x96\xe5\xa2\xc2\xe6\x9c\x13\xd5\
+\xa2\x19\x16\xad\x0aY\x92\xb2!5,\xc1\xccA\xcb\xcc\
+\xf6\xa9E\xf5B\x02\xd0\x02.\x82,\xea\x04\xd8\xc9\xfe\
+\xfc!\x1b\xc5\xed\x89\x05\xb6\x99^\x10T\x1fEy\xb6\
+yT(\x05\xe2\x9db\xa5\x17!qzP R\xdb\
+L,\xe0\x1aO\x9a\xf2\xfbQ\xf9Wg\xba\xae\xf5\x00\
+\x8c\xcb\xc8\xa7\xbbI\xe2\xfa\xe6|\xden\x94\xb8k|\
+\xc6\xdd\xd9\xe2\xef\xee\xe1\xbf\xe5\xcc\xde\xa3'9\xba\x9b\
+\xaf\x0eh\xbc\x9b\x87\x22i\x08j\x13(\x22\x90A\xd9\
+\xfavg\x03Mi/\x97\xce\xdf&\xd3\xcc\x82\x82\xe2\
+\x93XDj\xa0\xb1\x8d\x9bw/\xca\xcc\x8e\xef\xbay\
+\xac\xeb\xd5\x22\x0a\x08\x05\xe4\x87p\xf3\xac\xd5\xcdoY\
+\xbf\xeb\xd6\xe1+\x8e4\xbd0a\xe0\xaa\x1f\x05/j\
+\x88\xd4\xf5\xa3\x88^<\x11\xb8\xebG\x91\xb4\xa8\xaa\xd1\
+;\x0e\x80\xb9\xa8Q\xc8\x8a\xb3`/\x22\x12V\x1d\xe9\
+2\x13S\x8cW\x1ci\xcd\xee:\xd2\x9a\xbd\xea\xdb\x98\
+K\x0a\xbc\xe3\x05)KDp\xae:R\x93\xe2\xaa\xc4\
+\xba\xeaH\x0d\x8a\x03Kj\x97\x85\xb6\xc5\x8dL\xad\xc2\
+\xba\x99]GZ\xb3W\x1d\xa9\xb6\xc5\x0d7\xedzR\
+\xc3\x02\x01\xee\xda\x05\xc7\xb2@\x04\x00\xae\x02\xe9VB\
+I\x03\xbb\x9e4\xbc@\x90\xa4WOZ+r\xc5\x91\
+\xd6\xecU?\x9aP2H4\xba~4\xa4\x18\xb3\xb2\
+V?\xeaY\xdc\x04\xddV\x1d\x96KI%\xd7\x8e\x1b\
+u*\x8a\x8a\x9e\xd5\x8d.2E=YV\xdd(\x12\
+\x15Tg\xef\xba\xd1\x87l\x00\xa4\xae\x1bE\xccb\x09\
+a]?\x8a(%<E\xde\xf1\xa3\x08\x05\x10 V\
+\xfc(p1C\xb4\xeaH+*+~t\xdb\xd8)\
+?\xbd\xd8\xe9\xdf\xe5\xe5\xf3\x83zy\xc4\xe2d\xc1\xfa\
+\x11\xb8\xf9\x8fk%;\x11\xd9\xff\xf7K\xb9\x8d\xf2\x90\
+K\xb9\xc7o\xb4Kz\xdce\xe7\xa4\x13d.\x00@\
+\x13\x82\x12n\xd4j\xbaDW\x0bv\xbei>\x85B\
+(Q_<\xc6\x93\xc2\x8f\xca\xf4|\xee?\xa8\x7f\xfd\
+\x86\xd3\x17\xc8_\xac\xbde\xee\xfbf}H?+\xd6\
+\xdf\x7f\x8e\x9f\xbf\xcb\xaa\xb0*\xf7\xf3\xb3~~\xf0e\
+*\xc4\x1a?\xc3\x94~~\xb1\x81\x1f\xc4\xe7\x00k\xfc\
+\x5c\xbd\x9f_\xc2&~\xfe\xfb5~\x0f.\xb7\x1a\xcd\
+.\xab\xc5\x80zv\x99\x83\xecp\x98\xd2\xf9|>t\
+\xdaI\x97\xb5\xedp\x84\x07\xcdc~\xbe\xb6rb\xc4\
+\xfa8\x83}6\xdd\x1b\x1d\xf6\xf0\x97.k\x19q\xb6\
+\xd4h8R{4N\xdf^c\xe3y\xee\xa0q\xe6\
+\xbfQc\x91\xdc\xc3\x00Dq{8`\xf1\xb7\xfd\xe1\
+b\xdc\x03\xc7\x00\xeb\x0a\xc7\xa8c\x17\xc8Y6\x1f\xbb\
+`\xd2\x9e\xba@\xc5\xda?\xef;{\x01)\x9a[&\
+\xfb\x1e\xbd\x00\xf5\xe9\xbd\xce]\xa8\xdb\x18\xa1 Ag\
+[\xa7qAM`]y\x87\xeb\x085\xf2\xa94\x83\
+\xeb{@\xb9\xfd{\xecP\x093E'\x88\xc5m\x22\
+%\x93\x84l\xcc\xb1\xc9\x1c\xc3{y|\xff\x03N%\
+\x0a!\xa1b}e\xa2E-\xba\xf0X\x96$\x86\x88\
+\x95]\x06\x9cd\x1f\x03<0\x1a\x9e\x9f\xb0\xf1x\x0c\
+\xa2\xc3\x86{\x1b\x8f\x14\x0a\xef\xc2\x93\xd8\x96\xda\xc1\xba\
+K\x0d\xea7\xf5\xdb\xfb\x1eJ\xb2\xc5fi\x82\x09\x8c\
+R\xdd\x06U\x17\x80\x9f\xa6\xea2B\xf5\xc11W\xdd\
+\xa6\x93X\x02\x14:\xc3U\xf5\x02\x1a\x8aR\x07`Y\
+@5 \x9f\xc6\x0d\xca\xc5\x18hx4V\x143%\
+'^X1\x89s>\x8d\xc94\x0a\x18\x93\xb0\xb6\xbf\
+\xb0\x90;!\xcadJP\x88\xc4\xc9\x9aK.\x99f\
+\x9c\xfb\x0f\xda\x88\x9d\x86\x9b\x8e\xc4\x9e rQ\x0f$\
+\xad{\x0b\xa5(#i\x1d\xc4b\x97\xe4\xec]\x92\xb3\
+.\xc9\x00\x90V\x14<\xc3\xf2ax\xab\x08\x89>\x99\
+\x1a\x97\x16<\xc3\xc9\x94\xa9\xa4\x03\xa2\x8eB\xec\xa8\xae\
+8\xad\xb01hg\xe5R\x14\x03\xc3\xce6B\xa6\x02\
+\x8aa\xb5\xd5\x09\x17\xcf\x04\xb2=}\xb1\x17\x1533\
+?\x8c?\xb6m6\xb6\xcb\xdeF\x85j\x1d\x9bB+\
+\x10VM\xca\xb1\xb8+Q\xdd\xad\xda\xa58\xebR\x0c\
+O\x22\x98B\xa04H\x91a*\xd0d\xda\x82\x06\x98\
+!\x13.\x9c@\x086A/\x0c\x09\xd6\xdcV/\x96\
+L\xe3\x1a\xa5\x0d;u\x8b\xdc\xdb\xa9\xb7pdp5\
+\xb1\xb4\xc2\xceH\x5c\x9d:A\x11\xf2\x1a\x0cU\x9aA\
+\x13CwR\x89\x87f\x08\xee\x84\xe1\x13+\xaaJ)\
+6\x99JIAs\xc0Q66\xec\xfd\x15\xf1\xa7c\
+c\xcc\x07\xb61\x1a\xb61\xdb\xdb\xc6(J\x0a%\xd5\
+5Jb\x85HS\xde\x99\x89\xe5\xf0\xea\xc6\x1c\x8b\x91\
+\x09\xc8\x9e6\x86%\xc4\xc8\x95\x0fec0lc\xc0\
+?w\x8e\x151\xe1m:\xc7\x9f=\x7f/~8\xd6\
+\xf3\xff\xf4[%\xc76\xad\xf2g\xcf\xdfgc\xac\xc7\
+\xf0\xfc\x87\x8c\x0a\x0e\x14\xa9\x8c\xb11\x1a\x19]\xfc\xf4\
+\x83|\xda*\xc8\xffy\xf8\xbd\xb1-\x92\x8c\x18~\x0f\
+\xb4\xc5\xe1\xa9\x97\xf1\xb3<c\xec\x07GL\xdf|\xda\
+\xaac\x1cU\xf5\xf1\xd3\xb0\xe3'\x85\xc7\xa0\xa3\xa3f\
+s\x8f\x8f\xce\xf87\x0a\xa3\xe0\x19\xf1\xa6\xe4\xa7o<\
+\x90\xc7@\xe7\xdf\xe9.8$\x8e9\xc7\xefZ\x9c\xc2\
+\xb9\xb3\xad\x0e\xa28\x88p\xd5\xc9\xaaBT\x1c\x00M\
+\xc7(d\xc3\x0a%\xef\xab\x10e\xd1`\xd4\xce\x89\xc7\
+Y \x08\xbdV\x92[1[=!\x0a\xad\xa0\x90\xd1\
+\x18\xbd\xb6\xe8\xcd\xc3\xf6\xd5+l\x11\xe8zV\xe3\x83\
+\x22\x18\xa8T]NafJ\xc4\x07\xbd*\xcd(\xbd\
+h\x84G\xfeX\x1b\x15|\x98\xb7G\xc1E\x11C\xad\
+\xbbu\x89\x04\x11\xb3\x86\xafV\xc8\x05\xb53\x88\x84\xa2\
+\x16.8|\xf2\x06QF\xda\xc3\xb8\x8a\x1c\xc0\x01'\
+S\xa2\x92\x14\x99\xb6\xb8DO\x8c\x18\xb1\xb8/8~\
+~O\xb4#bv\xc4\xa90)\x9a\xec\x150\x91\x82\
+\x99a^\xad\x8c:$gk$g\x1d\x92\xe1/\xec\
+\x98\x01\xa9L\xa0hcNE\x83\x04\xd4'R\xc4)\
+\xd4c\x82$\x85\xcd\xbd\xc1\x0e#\x0b\xa59\x8f\xc2N\
+\x86\xb1c\xde\x13;/i\xd1\xc1\x8e\xa3\x88\xb0q\x17\
+\xbajh\xf5v\x076\xd2\xe1v)\xc8\xd1\x02\x02\x05\
+\x0d\xd84\x1b\xf8\x048\x09y\xc2\x85=\x0c\xad\x9d\x12\
+\x83\x82\xc9\x82\xb1\xf8\x96\x13\xa2j\x8e3;\x1a\xf6k\
+d\x1f\xd7\xccE\xf7 \x17\x19u\xa6v0l=+\
+1\xder\x22\x8b\xa2{R\xd7tB!\xb2.v_\
+\xa59\xeb\xd2\x0c\xda\x10e\xaa\xb0\xb66\xe4\x0a\x94\x18\
+\x13,\xa0\xee\xc4\xd6\x5c\x05\x13p\xdb\xe4p\xe1\xd3 \
+'S\x8a\x22\xe4\x068\xc6\x84h\x8bx\x93\xe3g\xcf\
+\xf5^\xecl\x1b\xcf\xf5\xf3\x0b\x90^\xfcd\x9b\x17 \
+?\xe3\xd7\x8b\x1f}\xc4K\x07F\xf8u\x82m&\xe4\
+\x7f\xb6\x8b>\xbb\xc0\x18\xf1\xd2\xe7\x13\xc4O\x0f\x8d\x9f\
+}\xc4\xcb%\x8e\x1fV\xa1\x1c\xe6\x9dk\xfd\x5c^\xf7\
+\x8bx\x0fN\xeb\xf5\xfc\xf2\xd5\xeb\x86\x1e\x8bf\x90\xe9\
+\x12\xce\x87=Y\x99\xf8\xb4\x85n\xb1\xfb\xb3\xa5K\xe0\
+d\xc0e\xd9\x16t\xa2\x98\xa6\xe0\x1b\x8b\xb2\xf6\xfd\xbd\
+\xfe/\xe8\x91\xbc\xf7\xeb{XX\xdc\xd4\x16\x05\xdf\xa8\
+t\xfd\xfc^\x8f\xf6\x16\xf8\x8e\xf6\xa8\x9eB]\xed\xc1\
+#\x1d\xc5pU}\x12\xf1\xa0\xae\xfaH\xc4\x89\x07S\
+\xdf\x82{>>\xc8\x84\x892^{e>PY\x95\
+\xb5\xa7\xaa\xc0\x00Xu|a9\xed@\x85\xe5\x8c\x1e\
+`%w+\xe8\xaa\xa3\x1a\xf2\x9e\x18l\xb8\x9c,\x9a\
+b\x11\xa34\x9fO\x97>\xd4h1\x0f\xe2\x854\xb6\
+\x0d\x82\xeb\xd1\x07D\xa9_\xe3\xd7O}\xc0\xd4\xc0\xa3\
+\xb0\xd6a5[\x16%\xa1\xc7\x8d\x97\xa4\x5c\x00\xa3n\
+\x0c\xae\xcf<\xf5\x0bdZ8{>O\x1e#w'\
+\xf5lNB\xd8\x7f\xa7V\xe5;{\xf1\xed\xe5\xf9_\
+\x9bM\xe7\xf7\x7fkn\xeeX\xd0a\x0eEG\xf0\x18\
+T\xeb\xcb\xc5\xdfV{,\x87{\x9e\x90\xc9\xd4\x5c\xea\
+\xcb!s\xa9\xd3\x07\x1c\xc5\x9d\xb9s\xbcY\xd6I\xf9\
+zw\xef7B\x89\xf2^\xe3\xa1D\xeb\x07\x80\xacM\
+C\xa7D\xf7\x18\x10%F?k\xc66\x0d\xb1.\x88\
+$\xbd\xfci\x83\x05\xc9y\x9b\x06\xf9\xb3\x8b\x02\x00\xf6\
+\xcb\xa0~\x19\x0am\x1a\x94!\xc4\x90\x99\xd9/C6\
+\xc8\xf06\x0d\xcb`\x8b\xcd26T\xb3I\x9b\x86e\
+H\x0e\xe8\xb1\xa1\xbe]\xdb4,\xc3@{\xf9\xf3\x86\
+\xfa\x8eY\x9b\x86\xf9;\xe2F\x1dxC}\xcf\xb8M\
+\xc32\x02e\xa3Mq\x7f}\xdf]^}7\xbf\x1d\
+\x16\x91\x88\x9bEl\xa8\xee\xf3\x8b6m!Cx3\
+T\xb1\x01\xaa\x8b&\x0d\xcbPt\x09\x8f\xe8\x95!\x1b\
+\xaa<\xa5M\xc32\x98t\xa3\x1eB\x1b\xcc\xf6\xacM\
+\xc32T137\xe8!\x1b\x9a\x9f\xb6iXF\x88\
+\x0a\x98\xf7\xcb\xd8P\xe7Jm\x1a\x94a\x10\x06\x00\xd4\
+/cC\x9d\x0b\xb7iX\x86\xa0m\xb4]\xc5~\x19\
+\x9cm\x1a\x96\x91\x14\x1aD\xfd2x\x83\x0c\x1eV\xc2\
+9}c\x85\xab\x8e\xee\xfb\x22#2\xd3\xfbe\xf8\x86\
+\x06h\xb3\x98\x0d5\x8e\x9eo\xef\x8c;\x84d8\xfa\
+\xb9]~\x92R\xc5\xac\xb3v\x91J\xa6\xad\xac]\x8c\
+\xe2NJ}\xcb\x06\xc3\xed\xfd1Mxl\xf0~\xd9\
+\xa6}c\x9a\x88M\x87ax\x9b\x06\xeb\x15$\xa5\x9f\
+?\xf5\xf3\x7f\x99m\x1a\xe4\x8f \xd9\xcf_6\xd8\xcc\
+\xbcM\xc3\xfc\x85\x09\x93\xb8_\x86m\x90\x91M\x1a\xd6\
+\x81P\xad\x9f\x7fl\xb2\xfb6\x0d\xf3\xb7\xb4M\x9dB\
+\xe4\x86z6o\xd3pl\x99\xb1\x81?\x1d\x80\x7fn\
+\x8c]#7\xc5\x95\xd2\xa4mb\xbe\xe0\xcd8m\xa8\
+k\xc16\x0d\xcbH\xd5\xcd26\x8d#\xb4M[\x04\
+\x01\x19\x91\xda\xefK\x01F\xfbkuHS\xe2~\x19\
+\xb4A\xc6\xbcM\xc32R\xa2\x9f\xff\xa6\xfa\xbeh\xd3\
+\x16\x9d\xb3n\x0e\x00`C};\xb4iXF\xf2\xe6\
+\x18\x1cb\x83\x8c\x97m\xda\xa2\x7f\xd6\xd8\xd8?#l\
+\x90q\xd1\xa6a\x19\x03>$\x91F\xda\x14\x1ek\xee\
+\xc1#\x0b\x12\x81o\x98\x810\xf7\x12\xee\x80\x87\x9c\x87\
+\x08\xa3\x9e>\xdbd\xf4`\x1e`C\xa7a6\xda\xe1\
+\x22K\xf4\xf3\x8f\x0d\x1d7\xb5i\x8b\x81#\xf7;s\
+\x87\x0d\x9d\xdelx\xe4k\x94\x1b[D8m\x10\x80\
+m\x1a\x8eX\x95bc\x8f\xe4\x1b*9\xcf\xdb\xf4\x11\
+G\xacV\x80X\xea\xd2;\xc5\x82\xc0J\xefD\xac\xcc\
+\xd1\x1b\xb1\xaa\xf4X\xbf\xda\x86\xb0\xf2e\x9b\xf6\x8eX\
+u\x83aR\xb4i\x9b\xde\x937\xf5\x0aa0\xa2^\
+G\x9fd\x97\xb2\xcf\xb9ni\xdbO\x9c\xf3\xffk\xef\
+\xca\x9a\xdb8\x92\xf4\xf3\xfaW0\xfc\xa6X\xaa\x94\xf7\
+\xa1\xf1:B\xa6\xad\x89\x89\xf0\xecN\xec<\xec\xa3\x83\
+\x92@\x8df$\xd3AQ\xbe~\xfdVv\x03l4\
+\x89&\x05\x8a\x1c\xcb\x07a\x19\xa8\xaf\xd1\xd9\x95_\xe5\
+U\x05\xa0\xcb\x8f\x85\x9e\xbf\xff]\xce\xe2\xfd\xd7\xce\x9f\
+\x9d\x9c\xe8\xd55\xf9\xdb\xdf\xe4\x8c%n\xc1\x06+\xec\
+q\xd3\xbf\xdeg\xdc\xd1\xe5\x05\xc9\xb4\xcf=\xce\xe4\xc5\
+\x9d\x92ax\x1b2\x8c\xdf\x9f\x8c\xd5\x8b\x93\xda\xc4\xf3\
+=M\x83M\x17\xd8X\x12}\x977\xc0\xe3\xb0\xdb\xd0\
+\x11q_w@\xe4\x84_\xf2~\x80\x00\xb7\xa0C\x80\
+\xf6\xb0\x0e=9\xd9\xe3~\x80 \x0bt,\x8a\xbeK\
+:\xc8nC\x07\xeda\x1d\xe5\xdf{\xd0\xc1\xb0_\xe8\
+\xb8[:8nC\x87\xc0>t\x10\xeeA\x87\xec\x15\
+I\x09\xef\x96\x8e\xe4\xdb\xd0\x91z_\xb1C\xd2\xffM\
+\xb1cY\xe7\x05\xae\x14\xf8\xe6}\xc9\xf5\x04/\xcf\xf7\
+o\xd8\x7f\x97\x15\xdecWi\xe1\x14~~\xbdd\xbc\
+*\xd9?\xc06\x14o\x93f\x15y/W9\x86\x17\
+\xefk\x1b\x8a\x0bivY\xf4\x1d\xba\x8aY\xde\x82\x0e\
+s\xbc/W1\xe7\x8f\xd5U,\xf2\xc6\xdd\xb9\xe1\xe4\
+$`OW\xb1\xac\xba\xf1\x16\x92\xe1&W\xb1\xe4\x0f\
+\xb0\x0d\xc7\xdb\xd4\x1c\x8et_\xb6\xe1(\xbf`\x09\xe6\
+\xcc\xb7\xa1\x83\xf5\xbeJ0g\xdf\xaf\x04\xbb\xe3[2\
+3`\xfe*o\xc9|\xfb\xfd>\xa6\x1d\x12\xfc\x9b\xc5\
+m\x15\xfcNvr}\x88\xd9\xb2\xfe\xea\xe6&\x0f\xa6\
+\x1fM\xc2\xd6\x86\xeaH\x8dA\xfcb\xdd\x87\xb3\xa9\x86\
+\xde\x91\x8aq\x8d\x8a\xfe\xe9]l\xf8\x10N,\x9b;\
+\x14\x04\xf6\x07\xd5\xafz\x9aqP\xfd\x10\xd6Z\xb0\xd5\
+c?\xfd\xe7;\x8a\xde\x9e\x80\xfcf1\x15x\xee\xb1\
+\xdfdJc\x99\x96\xabK\x87\x0elm\x8b\x1b\xd6\x94\
+u\xda\x147\xa5\xb7\xcd\xeeH\x0d\x84e=\x02\xf7\xd1\
+C\xb7T\xe0Y\xef\xc3t\xd6\xfbj\xdfQ\xef\xf1\x9a\
+\xde\xf3\x1d\xf4\xde\x1b%O\x9d\xd7j\xdeU\xdf\xe9\x9a\
+\xbe\xeb>}\xb7\xad\xbe\xcb\xd4\xf7h\x00@S\xe7m\
+h\x8fQ\xfd\xc5\xea\xe4\xed\xe7\x9fM{\xa2\x1d\xbfY\
+\xbd\xf8\xfe\xd5\xea\x87\x99\x22?\xbc\xfa\xf6\xc5\xe9\x0f\x0f\
+7_e\xb7\xf0Ow\x1d\xdf|\x81\x1d\x88.E\xfc\
+\xe3\x97\xab\xbe\x01S\x7f\xcf\x7f}\xba\xe3\xd0:\xd3\x0c\
+\x9fx\x8c\xea\xbe{\xd5\xb7f;}\xbd\xea\xf1\xe0\xf9\
+\xaa$n\x0e\x9c\xf5K\xec\xc0O\x9f\xfd\xb3\x13\xbd\xeb\
+\xc8\xb3\xd3\xb3\x17\xab\xb3\x8b+\xe0\x0c\x1e\xb2^\x1f\x07\
+\xab\xbf\x91\xbc\xea\xcf\x06\x1e\x8b\x83\x8b\xb1yv\xdc\xb9\
+\x9eu\xfe\xe7\xd3\xd3\x1e\xaa\xa8\xa9\x12!\xeb\xfc\xe0\xf8\
+=\xe7\xa6$pe=\xb7V\xdb\xa9\xa9G\x04\xed\xa4\
+\xb2b\x98\xc1\xceC?\x95X\xbf$\xf0\xdd\xd9Y7\
+\x8f\x87\xaf\x8f\x7fZ\xf5\x9e\x7f]O\xdf\xac\x13\xdd?\
+N\x7f(\xda*k\xbc[MPQ\xfcv\x02'Y\
+\xc3\x91\x87\xcf\x9e\x9d\xfe\xb8>\xba\x95\xeaK\xd0T_\
+\xfc\xb9\xb7\x9e\x9e\x9d\xbe\xf9\xdb\xd9\x0a\xc4\xfe\xbe:?\
+\x7f\xf5\xed\xcb2\xf3\xfa\x1b\xf3\xea\x8f?\xd5)kh\
+L\xf8\x95\x8b\xbf\xfbq\x06\xfd\xb4\x0d\xbd\xedc\xd5\xe5\
+\x14{\xcd\xcc\xfc\xf2\x81\x9f\xae\x1c\xd8\x8c\x17\x00\xf4\xfa\
+w\x0d\xae\xde|\xb7\x13\xdf26\x9a\xde\xba\x85\xca\x84\
+\xae\xaf\xd8/\xb8\xc1\xbe=~\xf6z5qY\x7f\xdf\
+\xbfz\xfb\xaa\x83#6:\xd5Uw\xfa\xfc\x93\xcf\xde\
+\xac\xce\x8f_\x1c\x9f\x1fo\xcci\xd3\xee3\xebO\xfe\
+\xe3\xb3o\xdf>~{\xf2C\x7f5\xbe|\xfd\xea\xf9\
+\xeam\xb5\xa6\xe6\xe0\xbe\x9b\xc2\xb0H\x9c\xff\xbc\x84b\
+\xfa\x11\xc9\xd4\x1c\xce\xfc\xcb\x97\x1d`4\x17&\x96\xea\
+b]\xe6\xd1t\x9d\xed\xab\xfe\xfd\xf4\xdd\xd9\xf3\xd5\x17\
+\xb5\xa3\xda\xdb[\x5c\xb2\x5c\xab;\xe2\x9b\xafW'\xe7\
+\xff3\x0c\xeeD\xcc\xfa2\xa7\xdf\x9d\xf7\xdd\xd9~\x1e\
+~\x1a\xb16\x9aI\xd5\xf3\xe3\xb3\x97\xab\xf3\x0d\x5c\xf2\
+\xe6H\xe92v\xa3\xffRb\xf5\xb4\xd7\x0a\xc7\xbd+\
+\x7f\xfb\xef?\x93\x8c\x8dbs-k\x0b\xad\x13\xaaj\
+\xea#\xda\x1d\xa5\xfb\xdf4\x82\xe3/.jPO\x8e\
+_\xaf=\xbc\x9fq\xbe:Z\x9b\xcf\xd3\xe1o\xc0\xbf\
+=\xfd\xebtdz\x7fw\x9e\xdas\xee\xf8\xf9$e\
+\xe8E\xb1<\xefG\xc1\x05N\x8a\xdeB\x7f\xb44g\
+%\xc5\xdf\x22\x11\x05/[I\x1d\x1b=\xe5\xb3\xb3\x17\
+'\x8f\xff\xf7\xcb\xa7}s\xd0\xe7\x8f\xff\xef\xf4\xec_\
+\xa3;\x16z\xfc\xec\xf4]'\xa3G\xae\x17\xcf\x1f\x9f\
+\x8c\xd7{\xf5\xa6G\xf6Go\xbf\x7f\xf9\x9f?\xbey\
+\xfd\xd9\xa3\xe9@\xbd\xa7\x82U\x9d\xbe\x11p\xb6z[\
+n\xd0\x9d\xfa\x1f\xe7\xe7\xdf=~\xf4\xe8\xbb\xbe\xa9a\
+;={\xd9\xcf\xeb\xff\xbdyU'<\xfa\xfby\xdf\
+\xd0\xf0/%wt\xfbu?\xfa\xab\x8b\xae=\xdax\
+\xf9\xe7\x9f|\xb2\xab\xd8\xee4M3\x85=\x8a\xd7\x9b\
+\xab\x82\x22~\x9c\x0f\xceg\x95\x8b\xabw\xec\xb5\x91\xd9\
+4s\xc4\xaa,w\x0ai\x80\x8aK\x920\x8c#\xe7\
+\x92bY\x92j,IR\x8d\xa3'1\x93D\xb0,\
+)M\x96$E>yz\xc4sI\xb4(\x09Y}\
+I\xd2\x17|t\xf4\xe5\xa5>\xc9\xb2$\xe7EI_\
+\xcaW\xf4U\xce%-3N\x90\xb9$\xe9\xab\xa3\xa7\
+\xf4T\xe7\x92bY\x92\xb0.Iz\xdaiz:\xb7\
+\x02\x86eIN\xb4(i\xf8\x9bK\x1a\x19\xbf\xfc\x99\
+\xf8M\x8e\x11\xfb9F\xde\xb5g(\xab\xaa\xcf5\xf1\
+\x91\x93\xddc\x8el\x86\xa2\xcb\xb6\x18O\xe2h&O\
+p#oa\xec)\xcd\x22\x96\xc7\xbf\x1es\x89\xbe<\
+jl\xbc<\xfe\xf5\x98K\xca\xbb\x1a\x7f\xc5EI\xca\
+\xb8O\x9f\x94\x17%\x85\xc8\xb2\x9f|q\x85'\xd5\x05\
+I\xb8(\x04\xbb\xdb\xf2\x5c\x88/\x19\xf6\xc2\x92\xe1\xb4\
+np\xff\x8b\x03;i\xdac\xd4\x8c\xf6e\xa8\xdcE\
+y.D\xd6\x0c\xcd\xf8\xb8\x91!\x84o\xeem\xdd\xe1\
+\xc3\x89\xc9; \xc6\xf1v\xc4\xe07\xf7\xb4\xa4\xf1\xc1\
+\xb4\xb8\xedK\x0b'\x7f\xc11\x17\x12\xb7\xa3\x85\xbe\xb9\
+\xb7\xd5\x92\xfd\x88\x89\x88'1O\xc9\xb1\x1c\xb4\x00\x9c\
+\x16%\x1d\xc5W\x91sI\xba,\xc9|1\x90>\xf9\
+\xe2\xc9\xd1\x93K\x92\xfc\x9a\x22H|I\xd2\x91\x1e\xd9\
+\x91\xcc%]\x93&\x10u\xb1\x08\xfa\xa2?\xe6\xc1=\
+\x97\xd3\x04\x03\xd2rp\xaf\xc7\x5c\xd22\xe3\x82\xd7\xa4\
+.\xef\x0f\x9bKZf\x5c\xcdsQ\xd2\x97\xf5\x98K\
+Zb\x1c\xf7\xf0\xb1\xcc\x05\xf7\xf8\xec\xe5\xe6m/\xd9\
+\xd6\xa1\xe6|\xe7\xdd\xb2\xb31\xb3\x1f\x22\xd7\xb3\x02?\
+\xe8s\xa5\xfa\xb9\xff8\x09\x9a\xd6/N_\xacj\xaa\
+\xd3\xbd\xe8\xf9\xfao\xb3\xbc\xb3\xebf\xc2\x82f\xe6\x9b\
+\xbd\x00X\x1d\x85\x0f\x1fR\xb6\xd4`\xee/\x11\x1b\x13\
+*\xcb\x83\xf9gP\x17\x9f5\xb5H\x8d\x04\xa1a\xb3\
+\xf8\xcdo\xde/\xef\x1c?\xceT\xc7\x8d\xe6\xc7\xd7\xec\
+N\x1b\x99]\xfd\xbf\x1e0\xb7\x08\x00\xe3C\xb4\x06\x9e\
+\x10x\xf0\xf56\x8a\xd9\xc0\x22\xbc\xa3\xc1M\xd36P\
+z\xdf\x15?\xa4!mA\x05\x18k\x07\xa2\x85z\x01\
+\xda\x00\x87\xb6\x04e\x89A\xf4\x96,\x87a\xcd\xd1\x81\
+\xa5\xcb\xa9\xe3\x0cY\x18\x0b\x15V\x88\xd2ah\x0b\xe6\
+9\xc0P@I\xaa\xb3\x0c\x91\x16:?\xa1\xe3\xfe\xfb\
+\xd3\xed\x1a\xd8\x86\x92f\x1a\xcc\xd9!\x9f1Tc\x01\
+\xc0XV\xa0 \xccV\x17\x99P\xc2f\xc2F\x1d-\
+:\x9cF\xc85ld\xc8a\x1b\x0a-W\x1f\x001\
+\x19\x81\x8e\x0f\x00DFIG\x82\xc6E\x91\xb7QJ\
+\x01\x0eY\x00!\x0e\xcd\xa4\x81A\xa0\xad\x16z\xf5b\
+l#\xeaB\x8f'\xf4\xe7%\xf3b\xb0\x90d\xd9\xd7\
+\xbcH\xf0\xc1\x9dY\xfe\xcd>\xb6\x19\xc1\x99\x16\xd5\xcb\
+\xb1SW?K\x9c\xd9\xbe6.\x92\xeb\x09\xa33\xb4\
+n#b\xcb\xcc\x01\xf1\xa2\x14\x80:H\x07G\xd5v\
+\xb8hk\xd4`\x8c-l\x1eY\x88\x86m\x10\xc12\
+\xd2\xa4\x96(\x87\x1e\xeb\xa1Ln\x14YmB\xac\x96\
+\x1e\xfa v\xf3z\x1c\xc5j1\x8b^\xe9\xde\xd8\xde\
+e\xd1y\x1f\x94\xf9\x83K\xc3\xbe\xcd`V\xce\xc7C\
+o\x99\xa1e\xecM\x0c\x82d\x83D\x03Bv?\x8c\
+&\x9c\xcc\xb6\x8dd\xc0\xa8\x98\xb7t\x01\x8aC\x84h\
+\xacH\xd1E\xcd\xc0H&-\xe9\xc8\xe2\xda\xa1,.\
+\xb0#\xa9\xe4\x8a\x13\xd2i\xb2\x16\x89.>\x802\x8e\
+\x1aJ\xa2\xe2\x88T[\x00\xcdhhSjra\x1a\
+\xec \x03\x86H\xcc5\x06P\x97$\xae\xd1\x82(\x13\
+(H\xd3\xc8j\xa0\x22\xdd\x0a\xf0j\x98(9_4\
+9\x1cTG\x19f\x1e\x87\xd9\x00%\x8b\xa5\x0d\x12M\
+\x9c\xd3\xa2\x00\xa2d\xee\x080#\xd3Ad\xb3H\x88\
+\x09\xf9zN\xf6\x8e\xf17\xbcq\xfc'\x13\xa8\x0c8\
+\xe5@\xe3\xc9io\xfc\xf0|\xb2\x9f\x9d\xa1\x03\xff4\
+Y\xd3\xd5\x0fz\xd7\x0e8\xef\xb8\x168Y\xd5\xe8;\
+\x95 \xd6.S\x80\xd9\x000[y\x06\xb0\x1e&\x1f\
+D\xa7\x95\xcb\xee*m\xd8\x80t\x5c\xaa1\xbc\xb2:\
+V\xf6\x82u\xc6\x81G\x9d_\xd9\xaa\xc4USch\
+\x8e\xaez\xf9\xc2?\x17S\xb7W6p\xa7\xb2\xfe\x1e\
+\xcazd\x01C\x80\xf0&\x22]\xa9AY\x19\x95\x8d\
+\xf4\x01\xb1RvH\xbb6*[\xea\x80\xd6\x19\xa5\x1d\
+!\x96v%\xee\xde\x95\xe5\x9d\xca\xe6\xfb\x8c\xacr\x01\
+,^\xca\x06t\xd5tPVK\xa1R\x7fD\xea\xff\
+\xd5\xa8W\xa3\xb2^\xca\xd6\x19\xc3\xc8\x8a\x8f#\xab|\
+{e\xafQPw)\xe88S\xf0\xf2\x85\x8f.\x03\
+\x09m\x0c_z\x90\x1d\x05)\x0e\x00;\x98\xd1\xf4R\
+7w\xd05\x072\x1a\x0dV\x1e\xb1f\xa4\xc2\xa5u\
+\xf0\xf2u\xe7\xcd\xb5\xfe\x8f^.\xa4\x82\x1e8\xbe]\
+\x8da\xff\xec\xdd\xeb\xd5\xe3\xd5\xf7\xab\x1eJ\xea\x9b\x92\
+g\xa7\xffZm\xca\x81us\xfc8\xfb1~\xf7\xe3\
+\x06(\xea\xfa\xc7\xa0\x8f\x9f\xbd;?\xdf\xc6\xfe\xd9o\
+\xc4\xd4o\xc8\xd4\xeb\x845\xba;\xa9\xb8\x1d\x12TZ\
+\xa8\xe7\x1dq\xcey\xde\xfb\xad\x83d5#\xbd\xb06\
+\x90\xc3\x8a\x9c\xeb\x17%\xea\x17\xd7\xb3&$\xf3\xf9\x87\
+\xe0\xa7;\xcbP'\xfb=\x16\xea\xf70\xe1\xf9\x05+\
+\xd2\xfb\x9f \xdeG\x05\xff\xfb\x9a\xfeL>g\x9a\xb2\
+\xf7\x08N\x1e+\xbf\xad\xc9\xc5\xcd\xd3\x03\x22\xd7\x07{\
+\x10v\x953\xcd?\xa6\x13\x1f\xc3tb\x8f\x11\xa7\xcb\
+\x13\xc2q>\xf1\xfe\xf3\x87\xad\x99\x07\xa6\xf3\x94\xfd>\
+\xc2\x19\xc0\x95\x92\xcf\xac\xa0}\xebc\xa2\xc4\xc9Q>\
+\xaa\xfa\x7fYU\xe7[\xaa\xca\x93\xaa\x1fU\xf5\xbf\xac\
+j\xc0-U\xd5I\xd5_\xe1<`\x07\x13\x08x\x99\
+\x8ak\xd4\xf7\x07\xf3R|\x9e\x0fYn\xaa\xeb?\x86\
+r\xbcz?\x15\xe4\xc37C/\xfdp\xe2\xf5\xf1\xb3\
+\xd5\xeb\xf5\xb7E\x0f\xea\xd8\xae\xaa\xad\x06\x14\xfa\xa3\x9e\
+\xd5\x1a\x90\x99\xc5\xe1\x10\xf9\xa2\xccd\xbc\xc6\xceS\x1f\
+\xe2pf\x15E\x95\xa6\xaa\xc0\xc3\xe6(&!\xab\x87\
+4\x8b\x98\xc4\xa27\xad\xc0$(\x19\x13\xfeiN\xea\
+\xa4\xf65\x1c\x1b\xc7e\x8eK\xa2if\xda{1}\
+V_\x89\xdc\xa0\x03\xed\xaf_\xf5\xa7\xc7\xb2\xc1^\x1c\
+\xf7\xef8\x9f\x9d\x1d\xff4vmD\xaf/J\x95\xf9\
+\xc1|\xa2\x1d\xde\xa2R7\x8dQ\x02 %\xbd7\x8b\
+\xf8d\xad \x89n\x08X\x183\xa7\x8f\x95f5\xc3\
++\x91R\xb5\x0c\xaa\xd5e\x904U@\x91C\xc3f\
+,H\xd9\xb1C\xa3\xe6!`<4\xcaK\xebY\x1b\
+\xa1&\xfb\xf6Y\xd6\xd84\x1c\xd7r\xbd!\xd5U\xc6\
+k\xa2Vs\x8c\xdd\x0e\x90\xc6\x1d\xb3\x06aX)\xac\
+1\x93\xb0\x0f\x18\x19\x90V\xc2v\x0c\x1fO\xd5\xe4\xa1\
+\x8f\x89\x0dA\xc1\xea\x8d\xd2\x92\x9c\xb4\x0a@\x000\xa1\
+\x8eqS\x0e\xc2\x83\xacFO\xf1\xf5\xa2\x84#\xe9\xd8\
+\xf0h`c\xa3\xcc\xd4m\xad|d\xa3L\xe8=p\
+m\x89\x1c^\x9c\x9a\xb9\x1a\x17\xe4\x9c\xae\x5c\x9d\xa7@\
+\x1aN\x14\xb0Q\xa1\xca?\x92\xccU\xa4\x80\x93K\xd4\
+\xf433Y\xa3.(\x86^YY\x0e\x03\x8a\x8f\xaa\
+\x88\xb8\xd98\x06,\xa3\xa0\xa2v8F\xb2\xeen5\
+\xa4\x0a\xb7I\x98\xe4\xa0\x1f\xf8\xc5E\xedPa\xe0a\
+\xbbs\x8a\x1b\xc2.\x948T\x1ax\x15\x9bT-l\
+\xe4\xbf\xb8\xa8\xb3.h\x92l\xc9\xbenp6\x8bM\
+\x03+\xb8\x8e\x94\x0b\xfaa\x8d\x02:*\xd5\xd0\xa8\x86\
+Q\xc7\xb8\x85G\x10\x96\x5c\x1fz\x84<\x8e~!\x00\
+\x1c\xce\x83Q:b\xd4\xe0\xa7:S\x87\xb0\xa5\x199\
+O\xb6\xbd#>\xb3b^\x80\xe77\xecT\xda[\xe8\
+\xec\x5c\xbb@4\xc8\xf1\xc0Cl\x88\x18H\xf2`\xdf\
+U0b\x83\x07\xef\x1dK\xca\xbb\xe7\x81$\xfe-\x01\
+d\x1e(\xcai\x1c$\xab\xd0\x0dI\x95u\xd5\x8d\x8a\
+\xeaC\x89\x8c\x9c\x96X\x96Qo\xd4\xc2X\xc41u\
+pM\x17\xc5\x0e%\xb9\x12\x0c\xb3S/\x87 \x1c\xa2\
+\x87\xb1\x00\x96\x9d\xa25#\xc8\xa4\x0a \xa2\xe8f\x07\
+\xa8c8\xe7\x8a#\x96 9\xc3\xa4\xec\x88\xc9\xeb\xec\
+\x09\xd5\xc6\x08\xa8\xbe-\xd1\x9aJD\xf8\xf6\xb5\xbd\xb1\
+\x99q\xb7\xcc\xa9\x9b\x95\xd7\xc1\x19ytj\x8f\xe0\xae\
+9\x124\x84\x90(2\x1c\x12p\x80(\x0dd\x98\x09\
+\x0a\x82\xf2p\xb2z@\x14AR\xfdA(4Z\x18\
+T%ZY\xcd\x85\xb4cuq\x8e5ff>\x04\
+*\x07\x8b\x9a\xe7Lh\x11\x9d@`34\xb4\x09\x02\
+H\xccP\xcf\x86\x12\x8e:C%Z(&\xe7\x1c\xad\
+X\xc7\xe84C\xd9[ \x88\xf8\x0cEj\x94\x1c\x94\
+\xa5W\xa1\x8eF\xe5nH\xce\xa6\x07\xa9M\xc1A\xab\
+fj\x00\x11\xaa\xa5\xbf&F\xd5\x9a\x0d\xd3\x82T\xc7\
+\xd9\xb5\xb99Z\x99H\x88\xa7QE\x03\x111+\xfb\
+\x920\xa2\xdcer?\x1f\xf4\x94e\xcd`\x88\x11\x84\
+\x8d$\x08J\xa7\x09\x15j\xa2\x9aZ:Y\xb4\x94\x0c\
+\x90-\xf4\xa8PJ7\xd0-\xd4\xbc\xb9\x93J\x14\x96\
+l\x9c<a3\x9e&t\xe2\xffh\x1b\xb5\x06`A\
+1]\xa70\x09'\xf3\xa9G\x13\xb6\xdd\xfb\x05\x14\xc1\
+\x9a+\xc9\x90p\xa3\x11\x09\x0aN\x96\xdf\xd1\x1d\xac\xec\
+\x0a{\x0ct\xf3\x07\x14\xa1\x7fZ\x9c\xb8\xb2\xd1\xc7\x1c\
+\xba\x96k\x1f\x0b\xbc\xa1\xf6qM\xcd\xb1\xf6\x910/\
+J\x19\x08T\x0a\xa3\xe0\x94\xa8:\xc4\xd4H\x0br]\
+\xf3NZ\xa4{\xac3_%\xa0A\xb0\xd6\xa1\xb1\xe0\
+\x88\x80\xd4\xa8Lg\x1e\x1eY\x98X\x92\x0e\x99\xce\x93\
+P\xf3\x9e2\x9d)\xdec\xa6[.\x9a\x97\x93\x9f\xfc\
+\x91\xfc\xfeH~\xf7\x93\xfcB\x9aY\x8a\xddmF,\
+\xb4\x83\x98\x7f\xe4\xc9\xdfI\x9eT\xc8Y\xac\x9bG\xd4\
+\xd0y|p\x9c2\x89\xe3\xd5L\xe2p5\x93X^\
+\xca$\x0e\x973\x89\xeb\xe5L\xe2z5\x93\xb8^\xcd\
+$.\x973\x89\xcb\x95L\xe2t5\x938N\x99d\
+1\xc6\xf3\xb5\xf5\x81\xfd\xea\xeb\x83\x9b\xf3\xe4\xc3)Q\
+\x226\xb7NX\xb4\x08\x17\xbe\xcdd0\xf6c\xec.\
+W\xee\xe6vL\xd2d\xed-\xe0\x5c\xde\xe2\xcdj\xf1\
+\xcdE\x98\xf3\x02\x80h\xa4\x1a\xd8\x81\xf9);\x5c\x89\
+\x98\xb8\xc0k?\xd5\xba\xb9\xae\xb8\xce\xe4\x1c~\x9d&\
+\xe7D\x97JR\xc468\xbc\xe6f\x19e{q-\
+\xd6\xabd\xb8\xb5\xb8\x16\xd3\xdaZ\xbd\x96\xe1m0\xfc\
+\xe1\xb4\xc26\x9d\xba\xb5\xc2\x96\xdb\x0bl\xc8\x0d\x18\xa9\
+#\x17\xab6\xa8\x0d\xd5\x0a\xbaXM\x9a\xf7oW\xe0\
+t\xd0\x0f\xf1\xa2l\x16B\xcb^t\x8d\x11\xd0G\xe2\
+EW\x9cf\xc9\xad&/\x1a\x01\x8f\xe6\x8a\x19\xba\x01\
+$+C\xa1\xd1\x15O\xdc\xc5<\x13,\xb1\xb6\xf7\x02\
+\xf6\xee@\xe5\xf2\xe0\x12k\x0dP\x9c\xd5o\xc9\xde\xb2\
+kp\xda\xdc5\xc6e\xc3N\x04\xd3\xb0\xca9_\x9d\
+\x85\xf1Yb}\xc0v\x12\x94\xf2\xde\xa6\x09-\x093\
+E\x0f\x1ffc\xb0\xb1\x0al\x99$d\xf9`\xb96\
+\x88\xd4\x0f\xec\xf7=\x8d\x9d\xfd\x02c\xf7\xe1D\xef\x9f\
+M=>\xe68\xa0\x8c\xa5\xa0qKd\xe3Z\x07g\
+lL\xaa4L\xe6\xdcI\x9c\x0e8\x9aJ\xa8\xc7\x10\
+\xc29\x01\xe4@\xac\x81&\x9a_`\x5c\xf546u\
+\x0a\xc2-\xd4\xb5%\x03a\xd6u\xc80C\xc7\xceh\
+\xb6\x84p\xe2\xdbE\x98H\xdf\x7f<\x02>\xda\xf1\x08\
+k\x8e\x95\xf3\x08\x1a{\x10nc\x12-D|\xf6>\
+\xcd\xc6\x86\x149\x96\xe2\x04L0\xce\xcb-\xc0\xa3\x06\
+\x03\x0c\xd5\x86\x94i\xa0\xc8| \xda\xdc(\xd1'\xac\
+\x06=\x9a1\x0a\xdb\x16\xca\x95\x03\xd3u\xc00\xc8{\
+'I\x1bE\xb8\xd6Hr*\xa0\xfc\x06\xec(\x11n\
+aG\xf4+\xf3k\x8a\x86D\x198\xd4O\xe6F^\
+c\x14\xe2$Y\x98eP\xd8\x01k3u-$\x89\
+\xc0\xa2\xc6\x92\x1aZ\x8ax\xa1\x0eb\xce%\xcf\x15(\
+\x0bbM\xe22\x0e\x19B\xe9p]!\x91X\xcfp\
+=\x0a\xa52\xc7t\xd0\x19*\xd9\x1c\x125g\xa8A\
+\x03%\x8f\xa1\x80\xa4&\x0cY\x86\x88\x8d\x9cI\xf1\xc0\
+\xbd\x05a \x95\xb93\xa1\x99\x0c\x13HL\x1c\xf5F\
+V\x87\xf5W4P!M\xea\x9d\x14\x0a)\x07\xc1\x0d\
+B\x98b\x90\x08FA{[R-j\xec&\xcb\x9b\
+\x00)p\x99.\x90\xa8\xea\x01gC'\xd5,\x0c\x01\
+\x1d\xfd@\xa0\xa5:\x04\x0f\x98\x92\xda\xe06\xd9\xea(\
+E\xa1\x90\x0eI\xa3DT\xb2\x01cp\xd3\xabW\xde\
+m\xd9y\xf1]\x88\xfaW7\x80\xf9\xfc\xff\x01\x9e\xd5\
+\xc9%:P\x01\x00\
+\x00\x00\x18\xd8\
+\x1f\
+\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xed}ms\xdbH\x92\
+\xe6\xf7\xf9\x15:\xcf\x97q\x1c\x99\xca\xf7\xccrw\xcf\
+F\xdcL\xec\xc6F\xf4\xc6]\xec\xce\xc4~\xdc\x90%\
+\xda\xd6\x8e,)$\xb9m\xf7\xaf\xbf*\x90\x12X\x14\
+-\xd0l\xda\xdd;c\xb8\xdd&\x1eTUV=\xf9\
+\x06\x14\x80\xc2\xf7\xff\xf4\xe1\xed\xc5\xd1O\x8b\x9b\xdb\xf3\
+\xab\xcb\x1f\x9e\x11\xe0\xb3\xa3\xc5\xe5\xe9\xd5\xd9\xf9\xe5\xeb\
+\x1f\x9e\xfd\xf5/\xff<\xcfgG\xb7w'\x97g'\
+\x17W\x97\x8b\x1f\x9e]^=\xfb\xa7?\xfe\xee\xfb\xff\
+5\x9f\x1f\xfd\xe9fqr\xb78;z\x7f~\xf7\xe6\
+\xe8_/\xffv{zr\xbd8\xfa\xc3\x9b\xbb\xbb\xeb\
+\x17\xc7\xc7\xef\xdf\xbf\x87\xf3\x15\x08W7\xaf\x8f\x9f\x1f\
+\xcd\xe7\xb5\xe6\xedO\xaf\x7fwttT\xc5^\xde\xbe\
+8;\xfd\xe1\xd9\xaa\xfc\xf5\xbb\x9b\x8b\xa1\xdc\xd9\xe9\xf1\
+\xe2b\xf1vqyw{L@\xc7\xcf\xc6\xe2\xa7c\
+\xf1\xd3&\xfc\xfc\xa7\xc5\xe9\xd5\xdb\xb7W\x97\xb7C\xcd\
+\xcb\xdb\xdf\xaf\x15\xbe9{UK\x8f\x9dy/C!\
+*\xa5\x1c#\x1f3\xcfk\x89\xf9\xed\xc7\xcb\xbb\x93\x0f\
+\xf3\xbej\xed\xe3\xb6\xaa\x8c\x88\xc7\xf5\xd8Xr\xb7R\
+/>\x5cT&>\xd9\x99\xe1\xe8\xba\xf4\xca\xfeu\xfd\
+\xfbP\xe1\x1e\x80\xdb\xabw7\xa7\x8bW\xb5\xe6\x02.\
+\x17w\xc7\x7f\xfe\xcb\x9f\x1f\x0e\xce\x11\xce\xee\xce\xd6\x9a\
+\xb9'\xbf\x93\xdbi\xe4\xf2\xe4\xed\xe2\xf6\xfa\xe4tq\
+{|\x8f\xb7\xfa\x9d94\xa0j\xf8\xec\xeeM\xdd\xe5\
+\x1cv\xdf,\xce_\xbf\xb9\x1b\xf7\xcf\xcf~xV\x07\
+\xcc\x8e>\xec\xdfw\xe9\xc5CC\x08\xc2\xc3\xa1{9\
+\xeb\x87t\xa3\xd6\xd9\xd5i\xedY\xed\xf7\xeb\xab\xf9\xe5\
+\xe2\xc3\xdd\xfc\xa7\xf3\xc5{\xa8\x02~\xee\x9b\xb8zw\
+w\xfd\xee\xee\xbfj\x89\xc5\xe5\xb2\xad:\xa8q\x84\xcb\
+\xc3C\xbd\x07\xb0o`\xf1\xe1\xfa\xea\xe6n\xfe\xea\xfc\
+b\xb1\x14x\xfc\xe6\xea\xed\xe2\xf8\xfa\xfc\xb2\x8e\xf0\xe6\
+\xaa\xfe8\xbd=\xbe\xfa\xf0\xf1\xf5\xe2\xf2\xb8\xd6\xb88\
+yy\xb18>9\xbd\xab\xb2n\x8fk\xe7.Nn\
+W\x9d\xbb\xbe|\xbd\xb5\xe9\x0fg\xd7U\x8d\x1e`[\
+\x0f\x7f\x1c\x0f\xff\xb1\x1e\xff\xfe\xed\xe2\xee\xe4\xec\xe4\xee\
+\xa4\xfe^\xd1z\x8fh\x0c%j\x99j\xb4/\xfe\xfd\
+\xcf\xff\xdc\xf6\x86\xfd\xd3\xd3\x17\xffyu\xf3\xb7\xba\xbb\
+\xdaZ\x81\x93\x97W\xef\xaa\x82\x86:\xabrg\xa7/\
+\xaa\xe1\xbc=\xb9\xfb\xe3\xf9\xdb\x93\xd7\x8bf\xa1\xff\xbb\
+\x1a\xca\xf7\xc7\xe3\x81\xae\xf0\xdd\xc7\xebE\x05\xbafo\
+\x16K\x0b\xdc\xe6\xb4\xf5\xbf\xb7\xe7\xad\xd2\xf1\x7f\xdc\x9d\
+_\x5c\xfck\x13\xf2\xec\xe8\xf8\xa1\x9f\xc7\xab\x8e6\xa0\
+\xed\x8e\xe3\xa8;\xf7\xc3\x1c\xf6\x1e\x0c\xa1)\xe5\xac\xf1\
+[\xd1u\xf6\xde\x9f_\x9e]\xbd\x9f\xdf\x9b\xa1G>\
+\xdb^\xe2\xden)c\xb3\xc4u\xed\xde\xed\x9b\x93Z\
+\xea\x87g\xbc\xed\xe0Uu\x8c:\x9ef\xa0\xb8:\xfe\
+\xfa\xdd\xf9\xd9\xe2\xee\xeabqsr\xd9H\xa0\xb5C\
+7U\xd4\xd6#W/\xff{qz\xb7\xfd\xd8\xcb\xab\
+\x9b\xb3\xc5\xcd\x83$\xda8pzuqu\xf3\xc3\xb3\
+\xdf\xfb\xb0\xad\x0e\xb5\xbe\xdd\x1fx5l\xcfFsy\
+yr\xbbX\xed\xde\xbe\xb9z_{U\xc1\xbb\x9bw\
+\x8b\xcd\x11\xfe|u\xf5\xb6\x0d\xcd%\xd1D\x1e\x11x\
+\xfa\xe1\x87gs\x12\x04\x16\x11\x7ft\xb4u\x96\x02\x9c\
+)?\xc5}m\x00?q\xa8\xd6V{\xdc\xe8\xbb\x9b\
+\x9b\x1a\xf4\xabW}\x5c\xdc\x8c\x01e\x1c\xcd@\xff\xed\
+\xf6\xf1\x0c\xc7\xe6/_^}X\x1d_\x99\xd9X\xa0\
+Rqo\xce\xd5J\xab\x1e\xaa_W\xac5\xf4@_\
+\x03X\x99\x1f\xc0\x9f\xceo\xcf\xab\xd3\x8f2\x87\xadF\
+\x8b\x0a\x9em\xa0-\x92\xd6\xacY;\xc0\xe0u\xbb\xfe\
+\xb0y\xe8\xe3\x96C\x8b\xb7\xd7\xab\xa3\xf5`\xf3\x97\xc1\
+\x1f\x1e\xbb\xc0\x80\x9f-^\xdd\x8e\xcan{\xec\x98\x8f\
+\xc6z]c\xeb\xf5\xe2\xb4\xa5\xc7\x95\x981\xb8.\xc7\
+\xde\x17\x95\x91\x851>_\xffW\xd3\xe0\xd1\x8b#\xd7\
+\xfa?\xdaZ\xe2\xe3\xb2\x04!\xb6\x7fpk\x99\x9f\x87\
+<\xb1\xad\x9d\xbe\x0b\xf3\xab\x9b\xf3\xd7\xe75\x88\x0f\xe5\
+tI\x94G\xab\xd3\xe9hmpZ\x1e\x02\xcc\xf75\
+\x87.Nn\xfe\xe5\xe6\xe4\xec\xbc\x1a\xd1z\x85\xfe\x88\
+h\xad\xf5\x10\x94n\xef\xae\xae\xdb\xef\xb1tCDm\
+\x94Y\xb9\xbb\xfbx\xb1X\x1e\x99\x0f\x9e\xf7\xe2\xf78\
+l\xdf\x0d\xd0\xca}_\xacW\xb9z\xf5\xeavQC\
+\x13\xd6\x0eN\x0b\x93\xcf\x17\x86[\x84\xd1\xc8\xc6q?\
+\xe8\xcf\xe5\x88\x8bMr\xc4%\x9e\xee\xb6\xcb\xa2\xbcz\
+u\x18\x8e\xb8\x94'\x85\xad\x22\xe1W\xe5\xc8q\x9a#\
+\xe7\xe9n\x1f\x8c#\xd7\xdf\x1cG\xc8\xd3\x1c\xe1D\xb7\
+O\xcf\x16\x8b\x83q\x84\xfe\xb4\xb03^\xe4\xe2\xec\x00\
+\x1c\xd5\x93\xca\xbb\xc5\xcd}\xc5\x96M\x11\x08\x19\x03\xc9\
+V\xed\x8d\xe7\xd5\xc0\xa8\xa48\xc6\x81\x8f\xcb\xf2\xac\xc5\
+\x1c\xe9\x1e\x1eO\xbc\x81\xb5\x14\xe2.0.%\x8ad\
+\x8c\x9c\xbfZ\xfc\xcb\xc9\xbb\xdb\xdb\xf3\x93\xcb\xffs\xf1\
+\xae\xf5f3\xf8\xd6a_,Nk\x93'\x17\xefO\
+>\xdev\xe4\x9c\xfdy\xf1\xd3\xf9\xc9\xdd\xfdY\xba\xba\
+\x99\x17z\xd6\xd3\xdaK\x10\xc9\xb2\xc6\xcc\xb2K\x9fi\
+5\xae\xa8SV\xe3:\xa5HLZ\xc8\xe2 V\xe3\
+\x8a\xf9\xb40\xc98[\xe8\x84\xb0Cz\x96\xd7m\x92\
+#\xf7\x89n\x97W\xa7\xf4\x8a\x0f\xe3Y\x94\x13Y\xcc\
+2\x16/m\x07a`;\xa8\xc4\x03'\xf4\x7f\xca'\
+\x96\xdb\xc4\xed\xef\xc8\xbd\xa3\xd1\x17r4scK\xce\
+\xa7\x1d\x8d>\xd7\xd1>\xd0\x0f\xcfB \x94]r\x0c\
+4\x15%\x03\x117\xd5\x07\xf4\x03\xd7\xb2\x09E\x8aH\
+\x19\xcbV\x94\x1c\xc20lD\x1f\x1b\xa7\xa9\x8c\xca\x19\
+&7^\xbc\xb9Y\xbc\xaa\xd7+\x8fR\xe8X\xee\xf5\
+\x0a\xfc\xeb\xe5\xf9]=\xc7\x7fw\xbb\xb8\xf9\x8f65\
+\xf1\x7f/\xffz\xbb~\x8e]\xa7}\xce\xfemq\xf7\
+\xe6\xaa\x8a\xad\x8d6N+\x0f\xd3#W\x08\xebG\xad\
+\xc0a\x99\x07\x1c5\xef6\xeab_k\xd4\x14\x05(\
+\x98\xb5\x1f9\x0b\x84\xa5\xf7#\xa7\x10(\x89A\xdd\xc8\
+\xdd@5\x89\xf8\xe9\x91\xfb\xc1G\xde\x97\xfaK\xbdv\
+\xbem\xb3\x14\xf5\x9a\xab\xfd\xbc\xa8\x13\x8f\x7f(1\xc3\
+\xe7;\xd1P\x1c\xd4S\xbd\xa3\xc1\x05H\xd2\xc8:\x1a\
+\x8c\x81)\xd5\xb3\xa7\xc1\x81Y\xd5\xe2\x09\x1a\xb8\x98\x1c\
+\xca\xec\xa7i\xa8\xf357\xe7\x1f\xfe@\x80\xec\xc5\xd1\
+gX\xff\x8c{sF`\xd4\x882\x9b\x13\xa4\x98\x87\
+\xf9Nde,\xb9\xeac\xc4\x1cA\x9c4\xd9\xbc\xb7\
+\x1ar\x08J\x8d\xde_\xd0A9\xcc\x9f\xa6\xcb\xff\x0e\
+\xe8\xd2\x80\xe2\xa9\xc1\xbd\x8b\xf9\xd2\xb6\xa2#K\x0b0\
+\xf5e+\x9a6pe\xe5i\xb2\xcand!\x7f\x15\
+\xb2\x0c\xeb&\x8d,/\xa2,\xb4FVk\xf0\xe4b\
+\x93\xac6\xa3DkCosH1Z\xc0Mu\xbd\
+q\xefU+\x9c\x09\x99\x142\xa2\xb5\x0a1\x81*\x93\
+tl\xf5\x22\xb9\xf8N\x9e\xe8u;\x18[\xf3Gt\
+\xa1\x9b\xfb\x8c\x99A\xc2)*Y\x0c\xea^<w\x22\
+kN\x0e\xee\xa9\x99\x1dg\xe9\x90M\x8e\xadS\xe78\
+\x92\xd4U\x1d\xe1\xae\xea\x93\xdc\xe5N\x96\xa6Z\x0e\xc7\
+\x1d\x02[\xbac%\x09\xc1\x98XC\xdb\xcf\xe4PQ\
+\x9d!(\xa1#\xd1\x8c\xd4\x81\xa5\xa8\xcd\x0c\x01\xcd\xac\
+\xd8\x8e9@\xc1\x1e\xa5\xc1\x82\x9e\xd2\x074T`\xeb\
+\x1c\xd4\x80\x9a\x98\xe4'\x1d4h'\x93S\xd4\x03\x9a\
+\xdc`j\x08\xe9\x84\xea2cJ\x88\xe6\x94*N\xe9\
+1\xc9\xcc\x10\xac\xa3\x0f\xe9s\x16\xef\x89B\x1d\x0b\xd0\
+X`:C\xe3l\x9eM]\x9c\xa2\xcfw\x1b\xf6\x13\
+\x1c\x0b\xeeh\x9a\xc8U\x17\x13'\xe0\x13\x1e\xd8\x9cJ\
+\x0c\x948K\xe9\x9c(\x1c\x0a\x9a\x17\xe9=\xae\x00\xc9\
+\x90A:gu}\xd6\xb94\xe3n\xc4\xcd\x89\x0b4\
+)\xd5\x0b\x18,\x8d\x8b\xe8b\xee\xfb\x90\xd8\x8fOp\
+\xb7L\xc2\xa5\xe0g\x90xzq~\xfd\xffN\xee\xde\
+\xac\x0b\xbe\xc7\x04mt\xa8{pk\xbf\xc7\xeb\xa9\xeb\
+\xb1\xad\xf1\xfa\xee\xe1:\xee\xbbz\xbds\xf1\xa2\xde{\
+\xfa\xc3\xef\x1f\x8f\xee\xf9pt>\x16\xbe\xbd\xbb\xb9\xfa\
+\xdb\xe2\xc5e\xbd\x7f\xbd\xfa\xbd\xbc1\xf4\x02\x81$\xb4\
+\xd4\xed\x1eo\x1c\xd4\x81\xbe\xb8\xb9zwy\xb6\x0e\xfe\
+\xf7\xd5\xf9e\x8f\xd6\x9b]\x8b\x9b\x8b\xf3\xfa\xcf\x0b\xbd\
+\xc7\xceN\xea-\xa5\x9b\x9b\x93\x8f\x9d\xb0\x86\x0e\x97\x9b\
+\xb5$\x90\xad\xe0\xadW\xa5\x95\xb5\x7f;\x9a\x13\x13p\
+b\x99q\x013t\xe5\xa3?5\x94\xc1\xdc\x9cg\x9c\
+\xc0n\x85\x1b\xa6\xe0\xe2\x16\x1dfP\x98x\xbd\xfa\x8f\
+\x15\xd6{\x8b2\x06O\xe7\xb2\x84\x83\x81\x0a\xdb\xa6\xb0\
+\x10\xd0\x08\xa1\xf5\x86\xc3\xc04\xd9;\xcc!\x85Kn\
+\x08K\x01C\x97\x9980K\xf1e\xa3\xa9\x10\x85\x90\
+g\x12`\x98\x9e\xd2\x81\x05,\x8asY\xab\xaf\x08\xe9\
+*64\xea\x08\x12\xe86s\xed\x84d\x00\x89\xb9\xf5\
+22A\x19%h\x1d,\x08ZH(\xd6\xaa\x17\x82\
+\x08G\xc9\xd6\xe88\xa0\x92\xa0Z\xc4\xb25;\x8e\xbd\
+\x14\x08Q\xcc5\x8eFl\xa4s\xac\xde\x93\x1f\x06B\
+\x12\xd8\xe0QU\x9d\xb0Q\xabc\xc3\xa3\xf6Gl\xb4\
+\x93^\x16)8\x86\xe58\xb0\xa1Q\x12\x10\xe6\xf4\x91\
+\x83updkl`$\xb65+\x01\xa1\xc2R\xd9\
+\xef\xc4\x8c:\xea\xa4\x8c\xda\x1c\xc1Q\xef\xeb\xf5G\x1b\
+\xf9q\xab\xed\xff\xbc1\x13r\xbd\x8c)\xb16\xffq\
+\x1fU~\xcb!\x9d\x99@E\xedK\x84t\xf9\xea!\
+]\xcb\xde!}S\x91\x8f\x03 \x93\x80[Z\x1f\x93\
+\x98\x14\x8a\x0a\xaf\x07@\xa6\x00$\xa5\xe8\xb0\x04.\x99\
+\x1b\x01\x90u\xc5\x7f\x1f\x00\xd9\x15,\x90\xca\x8607\
+H\xd3B\xeb\x0d{@aK\xef\xb0\x02Lh\xb9!\
+,\x0c2\xa5\xf4\x01\x90#\x80<}=\x00\x8e\xe0\xe8\
+2c\xfd.\x00\xb21\x84&\xb7\x00\xd8\x09\xb9\xf7\xd3\
+^\xc6\xe8\xd2#8:\xffX\xbd\x0b\x80\xe3\x80\xba\x98\
+4\x8e}\x8c?#G#6\xd29V\xef\xc8\xef\x02\
+\xe0\xa8\xaaN\xd8\xa8\xd5\xb1\xe1Q\xfb#6\xdaI/\
+\x0b\x1dJ\x1am\x04@F\x83@\xd4.\x00\x8e\xe0\xc8\
+\xd6\xd8@\x17\x00Y\x10\x881[\x00\xec\xc4\x8c:\xea\
+\xa4\x8c\xda\x1c\xc1Q\xefc\xfd.\x00\x8ec\xea\x02\xe0\
+~\xa7B\xf2?\xeeT\xe8\xd3!\xbd\x0fe_\xfa\xea\
+c\xff\x0b\xa3'\xaf_8\xfe\xf1\xae_\x0a\x01R!\
+\xe4C$:\xca]\x13\xdd\xdf\x0f\x81\x99\x87$\xd0\xff\
+\xfe\x09\xecO\xb7\x0eL \x96\x7f<\x0b,zH\x02\
+\xe3\x1f\xd0\x02\xed\x90\x04\xd2\xae\x04~K\x22['\xb8\
+\xcbA\x93\xc8?\xe4%'\x97\xc2\xbb\x92\xf8m*\xf6\
+\x93$\xe6\x97\xb7\xc4\x03\xdeo\x9f+B\x98&\xcb&\
+\x13_KS\xdbI\xd4\xafi\x89*\xa0\xa1\xe1\xdc\x8d\
+\x8f\xd0\x80C\x95\xbb\xf1\xb9C&%Z7\xbc$\x10\
+\xb6\x08\xebF\xe9:\xf1\xb8\xc7\xf4\xed \x84 \x16\xcd\
+v\xe3\x8c\xd8\xd1\x92f\x08$j\xc1Z\x7f\x85\xa3:\
+\xc5,@\xdd\x8c\xd1f\x8c@\xa1$\x87\x08\xabR\xbe\
+\xe9\xe1\xf3\xf40'D0Q\xcdC*B\x88\xf2k\
+\xcf\x06\x12\xe9An\xf0\xf4s\x19\xfd\x98v\x9f\xcb \
+\x07-\x86\x88\xa9\xbf\xad\xfb:^\x00\x8b\x84\xcd\xd8\xc0\
+\xa5\xe0r\xa61\x08XRK\x19\xe0\x82%\xb3\x82\x02\
+\x1c\xe9<c\x07\x0b7\xb1\x8a)D\x12\xd7\xea\x09\x84\
+\x11e\xa8^\x08\x02\xadH\xce\xd4\x00\x855l\x04\xcb\
+,\x18B\xcd\xb1\xac\xd5\xcf\x02\x1e\xc8\xc5[}\x0bH\
+s\x0b\x9e\x11:X\xd1R\x8b\x0a\x02\xa9\xa8\x94\x07\xb0\
+\xf6\x89\x04\x982\xfa\xfa\xb2\x14\xf4 'W\x08?t\
+\xc7\xc7\x9a}\xcf\x9b\x9e\xd4\xc9u\xc6\x0a\x99\x051\xda\
+\xf4\x17\xb89\x935\xb0\x109g\x05\x15\xeek?\xd0\
+\xc69\x90\x996\x13\x02qW\xf3\x01$d%\x9d\xc9\
+\x927\x8c\x87\xdaR \x8a\xf1J\xb6\x02;\x91\xe8\xcc\
+\x10\x14\x0b\xb9\x8d \xcd<*\x88\xe4\xa3\xecH@R\
+\xd4\x8131\xd0\xac\xdbpm\xe9\x1c\x85\xablc0\
+\x22\x92{\x8c*\xe6\x02\xc4\x1b\x95C $3\xca\x83\
+\x94\x18\xc1|\xe8O\xdc\xd7\xee;\xee\x08^\xc8\x0a\xcd\
+$@\xd9\xa3P\x15]\xa08\x15\xe3\x99\x08D)\x82\
+\xad6\x01\xe7P\x1f\x9b\xba\xee\xeb38\xa2\xb5\x98\x13\
+`J\x1c^\xc1fx\x85$\x9a\x09\x9a!\x9bn\xb5\
+\xd6\x9f\x8f\xaa\x15\xab\x0e\xbdb\x07\xb1{Uj\x02\x9b\
+&G\x83[\xafHj\xaf\x08\xcc(\xb2\x82\x05\x92I\
+\xdd\x96`\xebe1\xb26U\xbeB\xdc\xee\x91?-\
+\x11I6\x9ey\x82\x9b\x0bQ\x05\x11\x88B\x93fA\
+@I\xa1Z\xe5\xc6\xca\xa4\x83\xc1\xf4\x9e#5P5\
+\xe4Y\x08\x14\xcc\x94\xac\x18\x83\x99\x96|\x00[m\x5c\
+\x9ae_[\x022\xd9(\x1e\x04q\x05\x1d\xd4\x9b\xf8\
+\xf5.\x89w=\xffq\x85\x88\x8cc\x19*\x86ZJ\
+3\xd3\xc2\xaa\x1c\x83\x08N\x16j\xc4\x94\xb0T\xabX\
+B\xac|d}(\x08dF\x85\x9b\xba\x884Vc\
+\xc1\x92\x88>(\x81\x15\x8d\x1e\xabe\xfbm3\x22\xdf\
+2\xc7\xfa\x0f\x91lK\x80\xbb'\x1d8\xd9\xf2WO\
+\xb6\x98\x07\xba\xf5F\x84\x8fr\x14\xb9\x03\xb3c\xf6I\
+\x8a<A\x02\x93\xd7\x93\x14\x05\x82\x12\x16[\xcfR\x14\
+\x04\x85\xc4r#\xd8gBJ\xb2\x8fij\x1d\x1c\xd3\
+\xd4\xd8@\x9f\xa7\xc8\x14JfYOS\xc4\x01\x1c\x16\
+\xde\xa5)B\x10#\xdc\xa8_\x04\x94]J\x8c\xa9\xea\
+\x1eT\x8c1[\x8d\x0dl\x8e\x80\x04,R\xcbz\xba\
+\x22J\x88L\xd3\xf5tE\xcc\x80\x18\x22}\xc6\x22\xb6\
+F-\xd1\x98\xb1V\xa0ht\x19kl\xa0OZD\
+ E\xd4\xc7\xa4\xb5\x0e\x8eIkl\xa0O=$\x0c\
+\xce\xc4\xb4\x9e\xb7H\x0b\xb8\x8a\xfaz\xe2\x22G`{\
+\xdc@ d\x10\x8f\xa9k\xc4\xc6\xcc5V\xdf\x1c\x80\
+\x05$K\xe11y-A,\xca\xb9\x9e\xbc\xc8\x12\x94\
+\xc4\xb2\xcf^d\x05B8c={\x913\xa4\x90\xfa\
+\x98\xbd:;\xee\xd3\x17)-\xbb\xd6g0R\x03\xc9\
+ [\xcf`\xa4\x09\x9eJ4f\xb0\x15(,\xd2\xa5\
+\xb1\x11\xees\xd9\x00\x07Z\x978H\x03XK\x9f\xcb\
+Hui\xf7}:\x22e\xb0\x08\xb1\xf5lFR\xc0\
+3\x84\xeeAmX\xac\xcc\xb6\xaf/\xd6\x14\x98\xba\x9e\
+\xceH\xa4\xb9\x0bF\xd7+\x91G#\xf8q\x0d\xee\x13\
+\xdb\x00\xa3\x17ZOl$\x0aJ\xea:f\xb6e\x0f\
+r\xe5O]\xc7\x028\xc3\xba\xd4\xd6\x06\xc6\x82\x22c\
+j\xebT\xd6e\xb7\xdd\xaf\x1e\xf8\x7f\xde\xd5\xc3\x964\
+\xfd\xed\x9ax\xffIs<d\x9a\x9ez5\x8c\x93&\
+\x9b\x99xwl\xfb[_\x9c\xf2\xc4\x9bc\xc2\x19\x9c\
+\x91\xad\xc8\x84\xf4]\xdf\x1d\x1b\xef\x863\x01\x0aq\xff\
+\xb6\x8c\x10H\xb8G\xf6o\xd6 \xb8k\x1aww\xc7\
+\x0bCVPt\xc7g\x87\x81E\x98\xb9\xcc\x08\x0a\x19\
+\x16\xa5\x03<B\xccl\xbb=\xa6\xad\xbe\x8b!L\xb2\
+\xa6\x0e\xcc\x99V:\xda\xacT\xd4\x12\xa3\xa3- K\
+\x08St\xb4\x8dew\xa5\xcdY\xbc\xd2v\x10\xba\xb0\
+|U\xba\x88\x02\x84\xc5s\x07\xba\x18\x81S2h\x82\
+\xae}\x07\xefn\xb1\xd3\xe0\x9dv\x0c\x1a\xfb?\xc8B\
+\xe0FN\x5c\xaaN\x7f\xbbt\xd9\xc1\xe8\x9a\x8e\xb1\xae\
+\x96_$\xc6\xba:>\x11c9U\x952\xf6\x8a\xb1\
+\xdb\xf3\xf7\xf4{XQ\x8c\x90\x96o{\x8c{\xf3\x02\
+\x16\xe2\xe4^\x7f\x0a\x14\x09cy>\x91\xaawU\xf3\
+xR\xc1`V4\xbd?\xa9\xa0\x04R\x93\xec_\xd9\
+b@\xc50\x19O\x1f\xb6\x96=\xed\xca~:o\x17\
+7\xda\xc5\xa6\x8a\xab\xfcb\x17l\xe2\x1f7;\xf5\x96\
+}q\xb5mo\xb1O-\xc5\xb1e\xfd\x98\xefj\x0f\
+\xa7\xa5\xc5\x16i\xf4\xb44\xe7m\xd2\x0e\xb5\x16\x01[\
+\xe4\x14Kl\x89\x9f\xcfR\xc4~,\xb1%\x7f>K\
+\xa7\xf4%YrU\x9f^\xd5Bs\x1f[j\xdb\xe7\
+\xb3\xe4j8\xc1\xd2\x8e\xd2\xf0\x10,\xed\x9e\x1c&i\
+t\xe2}h|\xf9*q\x0f\x1a\x9dt\x82\xc6Ii\
+\x87\xa7Qh\x9a%\x91=\x5c\x12%p/\x96\xc4>\
+\x9f\xa5\x97\xafl\x81_\x90\xa5\xe9\xf0\xee{\x86w7\
+\xb7}X\xd2\xd8\xc7\x96\xce\xaa5})\x96\xd8\x1c{\
+\x96&:c\xe5\xb1\x81LP8\x06n\xe7\x8e\xa5)\
+iy\x86\xb8\x934\xda.M\x0fgK\xa1\xd3\xb6\x14\
+\xfe\xf9\xb6\xf4r\xcfS\x05\xf7\xc8}l\x89\xea\xf6\xa5\
+lIXbzA0)\xfbx\xdc\xe2e\xbe\xfc|\
+\x96\x84\x95~kI\x90K\xc1)\x96j\x99=r\xdc\
+\xe9\xb0\xed\xc8R/m\x9f\x1cG\xed\xcf\x97:\xa1\x12\
+d\x9a\xb4%\xe4=r\x1c\xe2.\x1e\xf7\xd9M \x90\
+\xb9\xb8\xb8~\xf7\x89e\xaf\xb6\x0e\xa0\xec`\xc4(\xb4\
+\xb5Igv\xa5\xca\xd3\x1e\x9d\xf5\x0c\x0e\x0e\xd9\xc5\x89\
+\x90'\x92\xfb\xeeb\xc5\x87?1e'\xdbW;\xdd\
+\xbeN(\x9b\xca\xde\xeb\x8eN\xafg:\xbd.\xea\xf4\
+\xea\xaa;\xae\xd3:q\x0d;\xb5\xdc\xd8\xf4$\xde\x13\
+Q\xc9\x83>o\xf6\xa0\x9f`\xea\x97\x13\x12\x82 \x0e\
+\xf5\xa9\x99\xab\x8a\x96\x04\xf2\xa0\xb0\x9d\xd6\xac!W\xb3\
+\x90\x875k\x8a\x13\xc5L\x1c0\x8bV|N\x90a\
+%\xb0<\xffU\xd9\xcc8\xe4ZX)\xa0\xc4e\x86\
+\xe0\x8ai61\x0d\xd4\xa9\x88\x09\xb0h)\xda\xa9\xa8\
+\xa2\x84T\xd1NCd@YH\xa4\xd3\x10\x07 F\
+\x9an>\xb8yPF\xeb\xf6\xd4\x03\xa8^\xf0\x90\x0b\
+\xd2\xb8y\x88\xd8\xca\x8e\x98\x95\x0b\xc6\x8c$\xc1]\xb2\
+\xcc\xe6\xa2@\x89Q>E\xf5\xf5\xc9Y7\xe1\xa5\x0c\
+\x81(\xc6\xfd\xe4\x18\x0aXb\xf7`\xf4XtD\xbb\
+\xa2[f\xe7\xbe\xac-\xa3>i\xcb\xc5\xf7\x88\x0cR\
+ \x94\xca\xe6;\x95$`\x9a\xd2\xdd0\xd9V\xb6\xa2\
+s\x83\xc2b\x9c\xb1\x9b\x93\xa8\x83\xcf\x18\xc8\x16s\xfe\
+\xa2\xce/\x5c\xec)\xc2\x02e\x0f\xc2\xe6\x8eP\xd4\xd8\
+\xa8g\x0c\x0dR\xd0zG\x9d[\x01%c\xb5\x8e2\
+5p!\xc6\xf85c_\xa0\xed8\xfc\xfdoy}\
+\xa0\xc9\xdbl\x13\xa9\xa7\xbb}\xf7\xeb\xd2u\xa8T1\
+}c\xb5\xd1Fd\xf0\xf8\xa6n\x10`j\xc1\x9c\xb8\
+\x01\xdc\xdd+\xfeUY+\x87eM\x89\x0b\x0a\xb7\x14\
+KEL\xf3\x8b\xe5X\x81\xe2\x84\xdaS\x9a\xc0bE\
+\x7f]\xc7%\xfa\xc6\xe9\xc19\x95\xdf\x10\xa7V\x00\xc9\
+\xbd\xc4\xe6\x0a\xc1\x8e\x8aB\x1d\xa7.\xa0\xa6\x86}R\
+&\x02\xb1B\xfa\x84\xf3O\x9d}m.k7\xcf\xec\
+\x16\xb5\xdb\x89\xae\x03\x9c\xd8\xa8\xb0N\xac\x048.\x19\
+8\xb5\xb6`C\x8bB\xa3e\xcf\xfb\xc0[\x17I\xdc\
+\xb6F\xe2\x9c\x0c\xac_#\xf1\x80\xa4\x89jy\xe2<\
+\x5c\x85ib\xd5\xc9~\x89\xca~\x1d\xcb\x89\xb5.O\
+\xbb\xaaO\x98\xd8\x84\xbdO\xfa\x11WB\x0fI\x1a;\
+>ii\x94\x13+Nw\xabSO\xac\xdf\xdd\xad\xf5\
+=ep\xd3~X\x12I\xb1\xac\xfc\x10A\x0b\x06\x1d\
+\x8a\x9c\xe9+;\x15\xd2\xce\xa2\x8aA\xa0\x11\xd2\xc6z\
+\xb1\x08\x22\xa4\xfa\x895eO\xb7\xd6<\xedj\xfe\x92\
+\xa7t\x18\x0fl1\xc8O[\x0cn.#\xecAI\
+}\xde\xcb\x84\x10\xd1\xf2hubS\xce\xde`\xd2\xc1\
+4(\x7f\x19\x09\x04\xc9\xee\x143\x01\xd1t\xe1\xfc\x9a\
+^\xb4q\xfa\xee\x04\x94\x8e\xee='\x0clE\xc9\xbe\
+\x16)\xf3\x82P\xac\x98\xcd\xe6\xd1~\x09\x17\xf9\xaa\xac\
+ho)\x01\xa4\x18E:V\x86\xe4\x84a\x1b\xac\x98\
+B\xbaYt\xac\xb0\xe4r@\xbf\x88\x96\x12\x87s\x98\
+\xe9\x8bn\x11\xf6\x89\xa5\xed\xbbe\xf0'\x96\xcc\xef\x96\
+\xd7\xdf+\x0f}\xcd\x91\xf3\xbe\xc9\xa5\xffLB\xff9\
+\x85\xe9\x87\xf4\xd8Y\xf7y\x06\x8f\x9d}\xfa\x0b\x19\x87\
+~\xcey\xfb\xdc\x16m{l\xa7\xbf\xcf\xb2\xf7WV\
+\xfa\x9bl>\x84\x99)a`\xfb\x7fg\xa5\x17\xc78\
+-\x8ev\xfc\xca\xca\xb40>\xd8\xedQ'\xdc_%\
+\xfd\xc7\x81\xa6U\xc2{s\xd4\x7f\x1ch'a\xba\xef\
+\xc7h\xd8\xd1\xa7\xbf\x12\xd5\x7fUj\xfa+T\xfdW\
+\xab\xf6sd\xcc\x1d\xbe)\xf5U\x1c\x19\xf7\xb7\x9a\xfe\
+Cd\xd3\x8a\xc4\x9d\xacf\xff\x0f\x91\xf5\xc2\xf4`\x9e\
+eE\x7f!G\xaf\xea\xb6\x13GV|\x0f\x8e\xa6\x85\
+\xe1vay8\x8e2\x7f!G.\x8b\xb2#G\xf8\
+59\xe2\x03r\xc4\xbf4B\x0f\xdb.\x1c\xa5\xee\xc1\
+\xd1\xb40\xdc.\xcc\x0f\xf8X\x82\xe6\xdf\xd1C\x09\x8d\
+\x90\xf6A\xda\xfak\xf5\xbe\xf9\xf8R\xb9\x04h\x12\xdb\
+\x8c\x18\xc8M\xd5\xeb{\xa5\x84\x06\xa4\x89>s\x02\xd2\
+\x88\xd4\xa3?U\xd4\x81\x84\xb4\x81i\x82\xc6\x03\x143\
+g\xc8\x92\xa8~\xbf\xdfJ\xaf~\x1a\x10R1]\xab\
+\xed@\xeaEs]\x8cC\x1a35\xe1\xe2\x10\xc3\xda\
+\x16D\x06\xc9&T[\x13\x067t\xa9`\x82\x9a\xc5\
+\x11;\xc4\xb0\x97\x9c\xca\xf7\xbbR\x1bX\xfe4(\xc3\
+V+/\x01\x06\xc2L\x97#\x11\x08F\xe3Y\x01U\
+\x0f\xb4\xdc\xc2B{\x89\xb5{#\x9f\x87\xe9\xb0\xed\xef\
+\xb4>\xfe\xde\xc8\xe6;\xad\xcb\xdd\x9bw\x17\x8b\x17\x8b\
+\x9f\x16\x97Wgg\xebo\xb9V-}\xd3\xcd/\xd0\
+\x8d\x98p\xaf\x9b\xf1\xa1%6\xf5$\xd7O.\xc6\xcc\
+\xc5\xf3 \xea\x0a\x86F\x0c\xa0\xb3\xd5\x91\x05\x812\x17\
+\xe2\x86\x11G\xe4Q H:\x96\xd2 \x95\xc2\xe9G\
+^Z-\xae\xdc\x04A6j\x0b8[\xddO\x9c\x91\
+\x83z\xc6\xc3^m\xb6\xfd+\x80mH\xb5A\x07t\
+\xc2\xa8\x0d\x22\xa4\xba{\xdf\x8b\x1f\xbb\xdd\x07\xde\xee\xb6\
+=T\x91B\x85\xa2\x0c\xf3\x8a\xe3^Q #,:\
+c\x10\x13J\xe3\xe7\x9b\xecs\xf0n\x9ea*\xf8y\
+T\x7f\xb7<\xa1\x5c66~E\xf5\xf9\xaf\xac\x02P\
+TEn&\x19E$*\xed\x01\x5cH]f\x05\x8a\
+\x17+Y\xf6WEh\xbaR\x0e\xaa\xa8\xbb\x05\x91J\
+\xce\xd2!-B\xb5\x8auH\x14\x8bG\xaa\x90B\x9f\
+r\x84@%*\x19\xdf=\xa1\x1d>\x90v~\xd7\xe7\
+\xa6Zo\xd1\xf2S\x9dA9]n\x9f\x8ax\x06E\
+\x08\xb9\xb4\x18\x91\xc4Tt\x08y\x04\x81\xec\xa5E3\
+,\x5c\xdc\x86 &@li3\x170rb\xaa\xd8\
+*\xdc\xcd\x5c!\x5c9c\xa8\x9d\x18Yk\x1b\xa4\xa9\
+J\xb6H\x16`,\xadM\x22\x84\xe2:hV\x04\x94\
+L9*\xaaCH,G\x5c@0,u\xc0\x04Q\
+m\xc4\xd6j\xff\xb8\x8e\x06\x94BDC\x84\x1bQ\x03\
+\xf2\x12\xc6-d\x9a\x9aZ4_N\x0b\x13\xde>\xf6\
+m\xe8\xe3\xf0\xa7\xa1\xbd\xd6\x9f\x88ur\x90X\xc7\x91\
+`\x86\xaa3&P\xd7\xa1\xaf\xdc8C\xd3\x98\x85@\
+\xa2\x17\x1b\xc6O\x0cA\xc5+j\xa0\xe4\x864`E\
+\xc9f\xe1\x90\x9c$1TF\x14\x5c\xaej\xe2\x84N\
+\xad\xc9h\xd9\xa1\x00F\xba\xb7\xc6\x92*e\x0c\xee\x98\
+u\xc7\x86\x9d4\xca2\xec\x8dE\x7f\x1c\xf6Y\xa0p\
+a\xe1V\xb5\xed#\x84\xa4X+M\x90\x1a$\xcd\xd9\
+\xd9\x94S\xb6\x0ej\x0b8\xfa\xee\xd4\x87\xe6\x102\x95\
+J\xe1\x990\x83\xa2\xb1\xcd\xe6\x02\xe4\x81\x99\xf6\xfc\xb1\
+\x1a\xe9\xb1\x1a\xd7\x17\xa6\xf8\x84\xd7\xfa\xf3\x8de2\x00\
+#\x02K|\xd1\x0f\x06\xf4\x16\xb4\x19\x06\xe8\xd3AZ\
+\x18\xc4\x5c\xa2R\xaf\xcd[\x15\xb3\xb9\x1e\x82%1W\
+\xd4\x00M\x1cc\xddu\x1c\x98\xac\x88m8Y\x14.\
+\x9d\xe7\xa9\x80\x16N\xe5\x0eu\x87b\xac!U\x90\x09\
+\x18\x12F6\x94\x22\xbc\x96\x0d\x03'v\xd1\x16a\xb8\
+8\x16;*\x02\xe2\xca63\x07\x16\xb1\xe0\x95;R\
+\xba\x0e\xbd\x8c\xe2\xcb\x93\x18Qp-h\xdaPt\x1d\
+\xe2\x08\x93\xba\x0eCD\xe3,[\x87\xfd\xe3Vt\xd3\
+\xbf\x99\x85w=\xf5\xb4r\x10\xff\xee\xbb\xe5.\xcb\xf0\
+H\xa0V\xdc\x07\xb4\xa8\x06Y\xd3[\x90\x09S\x1b;\
+gA\x1b0\x0a\xc5\x94\x86%\x17,\xbc\x0c\x84\x85(\
+\xc4\x9a6\xb1`\x9a6\xcc\xc3E\x07L\xc2\x82\xaca\
+&m\xcc\x0d\x0b\x0eOY\xd66N]\xa1\xe2N\xb1\
+,iE\x06\xc8027*[\x89\xb0eeu%\
+\xd2\x86\x16!v\x1e0\xcc\xa1\x93\x01D\x9aKL\x82\
+\xc2K\xc3\x04M4V\x11\xdcK\x90\x0f(\x99k.\
+KJ\xf0\x00q`\xe4Fe\x09\xd5U\xdd\x8aR\xc3\
+\x8c\x0b\x97\xd2[pH\xf8\x06T4\xa8\xe4C\xe6\xd0\
+\xc2\x03j\x89.\x1b%=%t\xca%\xa8\x00\xa2\xb3\
+\xd1\xa6\xa3\xb08!\xafP)\x1e\xd1\xa1\x82\xa0\xce\x85\
+\xac5\x9b\x94\xc9+?MUod\x18hJ\xb27\
+sO\x0b'i\x98%K\xe6\xba\xa78T\xa8X\xeb\
+Ua`%$\x9e\x99Aj\xaaSm3\x12\xc4\xd0\
+\x9cf\x8ePP\x92\xf4\xc8\x11(\xd2\x88[*7J\
+B?Rjn\x8c\xe2\x83\xeb&\xb35\xcbp\x84\xd0\
+b*\xad\xa4\x17\xb7\xe5\xe9X\x11\x1b0\x02\xe1\x94\xb0\
+&[$8K\xf3hcV\xd4e\x8f\xc4\x8b\x8a\x0e\
+\xa8\xa9\x96\xaa\xf2\x86zI\x13i\xa8\xaa\x9a\x97\x16\x10\
+Z\xd78\x1b&\xaa\xc5}\x15$\x04\xa9\x8b\x12\x0d\x15\
+&\xcb\x01E\xd2hcw\x06\x0cE\xb5\x99(P:\
+\xd2\x93\x11%\x85)\xe8\xfe\xa4\x81\xa9\xb1\x1c\x19\x8c1\
+x\x1fFX\xc5\x18R\x22\x9c\xbbX\xdaP\xc7\x94\x18\
+\xd0,\x91<`\x91\x962`\xa1\x1a\x0d*HE\xbd\
+w\xf2e\xba.\xbcD\x991\x1bf\x82\x1a:`F\
+X|k\x88\xf8q\x1b\xba\xe5|\xc5w\x8fg\xfe-\
+\x9e}\x8bg\xdf\xe2\xd9\xb7x\xf6\x1b\x8eg\xc6\xbas\
+<\xdb\xe7\xfa\xeb\xfb\xe3\xdb\x9f^\xff\xf1w\xff\x1f\x87\
+I\xee\xb2\x11\x94\x00\x00\
+\x00\x00\x19\x91\
+\x1f\
+\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xed}mo\x1c9\x92\
+\xe6\xf7\xf9\x15:\xcf\x971\xae*\x14\xef\x11\xf4t\xcf\
+\x027\x83],\xd0\x8b;\xdc\xce\xe0>.d\xa9d\
+kG\x96\x04In\xdb\xf3\xeb\x97\x99%\x89E)[\
+Y\x96J\xee\xde\xeb.\xb7\xdb\x95O2\x18\x8c\x87\xc1\
+\x88L2\x8b\xf9\xdd?}\xfep\xba\xf7\xe3\xea\xf2\xea\
+\xe4\xfc\xec\xfbW\x04\xf8jouvx~tr\xf6\
+\xee\xfbW\x7f\xfb\xeb?/\xf3\xd5\xde\xd5\xf5\xc1\xd9\xd1\
+\xc1\xe9\xf9\xd9\xea\xfbWg\xe7\xaf\xfe\xe9O\xbf\xfb\xee\
+\x7f,\x97{\x7f\xbe\x5c\x1d\x5c\xaf\x8e\xf6>\x9d\x5c\xbf\
+\xdf\xfb\xd7\xb3\xbf_\x1d\x1e\x5c\xac\xf6\xfe\xf0\xfe\xfa\xfa\
+\xe2\xcd\xfe\xfe\xa7O\x9f\xe0\xe4\x06\x84\xf3\xcbw\xfb\xaf\
+\xf7\x96\xcb*y\xf5\xe3\xbb\xdf\xed\xed\xedU\xb5gW\
+o\x8e\x0e\xbf\x7fuS\xfe\xe2\xe3\xe5\xe9X\xee\xe8p\
+\x7fu\xba\xfa\xb0:\xbb\xbe\xda'\xa0\xfdW\xad\xf8a\
++~8(?\xf9qux\xfe\xe1\xc3\xf9\xd9\xd5(\
+yv\xf5\xfb\x8d\xc2\x97G\xc7\xb5tk\xcc'\x19\x0b\
+Q)e\x1fy\x9fyYK,\xaf\xbe\x9c]\x1f|\
+^\xf6\xa2\xb5\x8dS\xa2\x8c\x88\xfb\xf5\x5c+\xb9]\xa9\
+7\x9fO+\x13?\xd9\x98\xf1\xec\xa6\xf6\xca\xfeE\xfd\
+{'p\x0b\xc0\xd5\xf9\xc7\xcb\xc3\xd5q\x95\x5c\xc1\xd9\
+\xeaz\xff/\x7f\xfd\xcb\xdd\xc9%\xc2\xd1\xf5\xd1F5\
+\xb7\xe4wz\xbb\x1e9;\xf8\xb0\xba\xba88\x5c]\
+\xed\xdf\xe2\x83|\xef\x0e\x15\xa8=|t\xfd\xbe\x1er\
+\x8e\x87\xefW'\xef\xde_\xb7\xe3\x93\xa3\xef_U\x83\
+\xd9\xd1\xc7\xe3\xdb&\xbd\xb9\xab\x08Ax<u\xabg\
+\xf3\x94\xde\x93::?\xac-\xab\xed~w\xbe\xbc\xb8\
+\x5c\xfdxr\xfe\xf1j\xf9\xe3\xc9\xea\x13T%\xff\xe8\
+\xab9\xffx}\xf1\xf1\xfa?V\x9f\xafWg\xeb\xfa\
+\xaaa\xcd\xca\xf5\xe9Q\xee\x0e\xec+X}\xbe8\xbf\
+\xbc^\x1e\x9f\x9c\xae\xd6J\xf7\xdf\x9f\x7fX\xed_\x9c\
+\x9cU+/\xcf\xeb\x97\xc3\xab\xfd\xf3\xcf_\xde\xad\xce\
+\xf6\xab\xc4\xe9\xc1\xdb\xd3\xd5\xfe\xc1\xe1u\xd5u\xb5\xff\
+\xa0\x81\x17g\xef&\xab\xff|tQ\xbb\xd3\x03l\xf2\
+\xf4\x97v\xfaO\xf5\xfcw\x1fV\xd7\x07G\x07\xd7\x07\
+\xf5\xfb\x0d\xbd\xb7\x88\xc6X\xa2\x96\xa9\xce\xfb\xe6\xff\xfe\
+\xe5\x9f\x87\xa3\xf1\xf8\xf0\xf0\xcd\xff;\xbf\xfc\xfbx8\
+~\x86\x02\x07o\xcf?\xd6\x8e\x1aen\xca\x1d\x1d\xbe\
+\xa9\x0e\xf4\xe1\xe0\xfaO'\x1f\x0e\xde\xad\x06O\xfd\x9f\
+\xd5a\xbe\xdbo'\xba\xc2\xd7_.V\x15\xe8\xaa\xbd\
+\x5c\xad=qj\xf0\xd6\xff>\x9c\x0cB\xfb\xff~}\
+rz\xfa\xaf\x83\x92W{\xfbw\xed\xdc\xbfih\x05\
+\xc6\xc3fG=\xb85s<\xbas\x88\xa1c\x8e\x06\
+~+\xba\xc9\xde\xa7\x93\xb3\xa3\xf3O\xcb[w\xf4\xc8\
+W\xd3%n\xfd\x972\xee\x97\xb8\xa8\xcd\xbbz\x7fP\
+K}\xff\x8a\xa7N\x9e\xd7\x01R\xed\x19\x1c\x15o\xce\
+\xbf\xfbxr\xb4\xba>?]]\x1e\x9c\x0d$\xd0\xc6\
+\xa9\xcb\xaaj\xf2\xcc\xf9\xdb\xff\x5c\x1d^O\x9f{{\
+~y\xb4\xba\xbc\xd3D\xf7N\x1c\x9e\x9f\x9e_~\xff\
+\xea\xf7>~nN\x0dm\xbb=q<~^5w\
+y{p\xb5\xba9\xbcz\x7f\xfe\xa9\xb6\xaa\x82\xd7\x97\
+\x1fW\xf7-\xfc\xc7\xf9\xf9\x87Aa\xa2z\x86\xdd?\
+}\xf8\xf9\xfbWKc\x08\xe7\xd0\xf2\xe0lmk\x09\
+ \x8e\x92\xf1\x13\xd4\xd7\x0a\xf0'NUi5\x7fP\
+\xe9\xc7\xcb\xcb\x1a\xfb\x97\xa7\x07_V\x97-\xae\xdc\xb8\
+\xcb]\xb1\xc1\xa4[\xb7\xac\xdeV\xf9\xacc\xb4bC\
+uw4\x0c\x00+\xf3\x1d\xf8\xe3\xc9\xd5I\x1d\xc0\x8d\
+\x8b\xf1SG~\x05\x8f\xee\xa1Cd\xacY\xb0\x1a\xc0\
+0\xf0~\xf1\xf9\xfe\xa9/\x13\xa7V\x1f.n\xce\xd6\
+\x93\xd5\xef\xd7~\xfd\xd0\x95G\xfchu|\xd5:m\
+8b\xc7|`\xebE\x8d\x95\x17\xab\xc3!\xdd\xdd\xa8\
+i\xc1rm{_T\x1a\x0b-\xde^\xfc\xc7\xd0\x15\
+{o\xf6\x5c\xeb\xffh\xb2\xc4\x97u\x09B\x1c\xfe\xc1\
+\xc92\xff\x18\xe3\xfeT=}\x13\x96\xe7\x97'\xefN\
+j@\x1e\xcb\xe9\x9a(\x8f^\xa6Z\xbda\x9c\x96\xbb\
+@\xf1]\xcd\x89\xab\x83\xcb\x7f\xb9<8:\xa9\xde\xb0\
+)\xd0\x9f\x11\xadRw\xc1\xe5\xea\xfa\xfcb\xf8\xdeJ\
+\x0f\x88\xa85\x9d\x95\xbb\xeb/\xa7\xab\xf5\x99\xe58\x82\
+\xde\xfc\x1e\xc7\xcf\x1fG\xe8f\x18\xbe\xd9\x149?>\
+\xbeZ\xd5\x10\x83\xb5\x81\xf3\xca\xe4\xeb\x95\xe1\x842j\
+l\xec\xf7F\x7f-G\x5cl\x96#.\xf1x\xb3]\
+V\xe5\xf8x7\x1cq)\x8f+[G\xb4o\xca\x91\
+\xe3<G\xce\xf3\xcd\xde\x19G\xae\xbf8\x8e\x90\xe79\
+\xc2\x99f\x1f\x1e\xadV;\xe3\x08\xfdqeG\xbc\xca\
+\xd5\xd1\x0e8\xaa\x17\x88\xd7\xab\xcb[\xc1!-\x22\x10\
+2\x06\xd2m\xd6l\xd7\xc9\xc0\xa8\xa4\xd8\xe2\xc0\x97u\
+y\xd6b\x8ew\xc6\xb6\x0bi`-\x85\xb8\x0b\x8ck\
+\x8d\x22\x19\x8d\xf3\xe3\xd5\xbf\x1c|\xbc\xba:98\xfb\
+_\xa7\x1f\xd7\xad\xe9\x83o5\xfbtuX\xab<8\
+\xfdt\xf0\xe5\xaa#\xe7\xe8/\xf5R\xf5\xe0\xfa\xf6\xaa\
+[\xdd\xcc\x0b\xbd\xeai\xed5\x88d\xd9`f\xdd\xa4\
+\xaf\xf4\x1aW\xd49\xafq\x9d\xebHLZ\xc9j'\
+^\xe3\x8a\xf9\xb82\xc98Z\xe9\x8c\xb2]\x8e,\xaf\
+\x9fY\x8e\xdcg\x9a]\x8e\x0f\xe9\x98w3\xb2(g\
+\xb2\x98e\xac\xde\xda\x16\xca\xc0\xe6\xd5\xb9\x07\xce\xf4\xff\
+!\x1fXN\xa8{\xc6@\xee\x07\x1a\xbd\xd0@37\
+\xb6\xe4||\xa0\xd1\xd7\x0e\xb4\xcf\xf4\xfd\xab\x10\x08e\
+\x97l\x81\xa6\xa2d \xe2\xa6-\x0e\x7f\xe6Z6\xa1\
+H\x11)\xadlE\xc9!\x0c\xc3\x1a\xfa\xd09M\xa5\
+u\xce8Y\xf1\xe6\xfd\xe5\xea\xb8\xdew<H\xa1\xad\
+\xdc\xbb\x1b\xf0og'\xd7u\x9a\xe4\xe3\xd5\xea\xf2\xdf\
+\x87\xa9\x86\xff}\xf6\xb7\xab\xcdk\xec:\x8ds\xf4o\
+\xab\xeb\xf7\xe7Um\xadt\xe0\xb4\xf20o\xb9BX\
+o\xb5\x02\x87e\xee\xd0j\xde\xce\xeab\xdf\xcaj\x8a\
+\x02\x14\xcc\xda[\xce\x02a\xe9\xbd\xe5\x14\x02%1\xa8\
+\xb3\xdc\x0dT\x93\x88\x1f\xb7\xdcwny_\xea\xaf\xf5\
+\x1e\xf8j\x98m\xa8\xf7\x5c\xc3\xd7\xd3:\x91\xf8\x87\x12\
+\x0b|\xbd\x15\x0d\xc5A=\xd5;\x1a\x5c\x80$\x8d\xac\
+\xa3\xc1\x18\x98R={\x1a\x1c\x98U-\x1e\xa1\x81\x8b\
+\xc9\xae\xdc~\x9e\x86:\xefry\xf2\xf9\x0f\x04\xc8^\
+\x1c}\x81\xf5O;Z\x8a\x03\xa3F\x94\xc5\x92 \xc5\
+<\xcc\xb7\x22+c\xcdU\x1f#\x96\x08\xe2\xa4\xc9\xe6\
+\xbd\xd7\x90CPj\xf4\xe3\x05\x1d\x94\xc3\xfcq\xba\xfc\
+\xff\x03\xba4\xa0xjp?\xc4|\xed[\xd1\x91\xa5\
+\x05\x98\xfa\xb2\x15M\x1b\xb9\xb2\xf28Ye;\xb2\x90\
+\xbf\x09Y\x86\xf5#\x03Y^DYh\x83\xac\xa1\xc2\
+\x83\xd3\xfbd\x0dSC\xb4a\xfa0\x19\x14\xcd\x03\xea\
+\xd4\x8d\xb5\xa3\xe3\xa1p&dRHC\xab\x081\x81\
+*\x93tl\xf5*\xb9\xf8V#\xd1\xebggl-\
+\x1f\xd0\x85n\xee\x0bF\x07\x09\xa7\xa8d1\xa8{\xf1\
+\xdc\x8a\xac%9\xb8\xa7fv\x9c\xa5C\x0ezl\x93\
+:\xc7F\xd2\xb4\xe8q'\xfa(w\xb9\x95\xa7\xa9\x96\
+\xddq\x87\xc0\x96\xeeXIB0&\xd6\xd0\xe1kr\
+\xa8\xa8.\x10\x94\xd0\x91hA\x82\xc0R\xd4\x16\x86\x80\
+fVl\xcb\x1c\xa0`\x0f\xd2`AO\xe9\x03\x1a*\
+\xb0u\x03\xd4\x80\x065\xc9\x8f\x0e\xd0\xa0\xad\x5cNQ\
+w\xe8r\xa3\xab!\xa4\x13\xaa\xcb\x82\x91!\x86A\xa9\
+\xe2\x94\x1e\xb3\xcc\x8c\xc1:\xfa\x90\xbed\xf1\x9e(\xd4\
+V\x80Z\x81\xf9\x0c\x8d\x8be:\xb0p\x8a\xbe\xde\xce\
+\xecG8\x16\xdc\xd25\x91k_\xcc\x5c\x80\xcf\x8d\xc0\
+:\xa8\xc4@\x89\xb3\x94n\x10\x85CA\xf3\x22\xfd\x88\
++@2f\x90n\xb0\xba\xbe\xea\x864\xe3v\xc4-\
+\x89\x0b\x0cZ\xea(`\xb04.\xa2\xab\xa5?\x85\xc4\
+\xde>\xc1\xed2\x09\x97\x82_A\xe2\xe1\xe9\xc9\xc5\xff\
+9\xb8~\xbf\xa9\xf8\x16\x13\xb46\xa0n\xc1\xc9v\xb7\
+\xfb\xa9\x8bVW\xbb\xbf\xbb\xbb\x8f\xfb\xe3q])z\
+S\xd7\x90\xfe\xf0\xfb\x87\xd6\xbd\x1e\xcf.[\xe1\xab\xeb\
+\xcb\xf3\xbf\xaf\xde\x9c\xd5\xf5\xe8\x9b\xef\xeb\x05\x9e7\x08\
+$\xa1\xa5~n\xf1\x81\x83j\xe8\x9b\xcb\xf3\x8fgG\
+\x9b\xe0\x7f\x9e\x9f\x9c\xf5h]\xb4Z]\x9e\x9e\xd4\x7f\
+\xde\xe8-vtP\x97\x86./\x0f\xbet\xca\x06t\
+\xbc\xdd\xac%\x81\xec\x06\x9e\xbc+\xad\xac\xfd\xdb\xde\x92\
+\x98\x80\x13\xcb\x82\x0b\x98\xa1+\xef\xfdy@\x19\xcc\xcd\
+y\xc1\x09\xecVx\xc0\x14\x5c\xdc\xa2\xc3\x0c\x0a\x13o\
+\x8a\xffPa\xbd\xf5(c\xf0t.k8\x18\xa8\xb0\
+\xddW\x16\x02\x1a!\xb4Yq\x18\x98&{\x879\xa4\
+p\xc9{\xcaR\xc0\xd0e!\x0e\xccR|]i*\
+D!\xe4\x85\x04\x18\xa6\xa7t`\x01\x8b\xe2\x5c6\xe4\
+\x15!]\xc5\xc6J\x1dA\x02\xdd\x16\xae\x9d\x92\x0c \
+1\xb7^G&(\xa3\x04m\x82\x05A\x0b\x09\xc5\x86\
+x!\x88p\x94\x1c*m\x06\x95*\xafE,\x87j\
+\x9b\xed\xa5@\x88bnp\xd4\xb0Fg\x13\xef\xc9\x0f\
+\x03!\x09\x1c\xe0\xd6U\x9d\xb2\xd6\xab\xad\xe2\xd6\xfb\x0d\
+k~\xd2\xeb\xa2*\x8da\xd9\x0c\x1b+%\x01aN\
+o\x1cl\x82\x8d\xadVA#v\xa8V\x02B\x85\xa5\
+\xb2\xdf\xa9i}\xd4ii\xbd\xd9\xc0\xd6\xef\x9b\xf2\xcd\
+G~\x98\xf4\xfd\x7f\xdc\x9b\x09\xb9X\xc7\x94\xd8\x98\xff\
+\xb8\x8d*\xbf\xe4\x90\xceL\xa0\xa2\xf6\x12!]\xbey\
+H\xd7\xf2\x8c\x90\xdew\xe4\xc3\x00\xc8$\xe0\x96\xd6\xc7\
+$&\x85\xa2\xc2\x9b\x01\x90)\x00I):,\x81K\
+\xe6\xbd\x00\xc8z\xc3\x7f\x1f\x00\xd9\x15,\x90\xca=e\
+n\x90\xa6\x856+\xf6\x80\xc2\x96\xdea\x05\x98\xd0\xf2\
+\x9e\xb2\xa8\xe2)\xa5\x0f\x80\x1c\x01\xe4\xe9\x9b\x01\xb0\x81\
+m\xc84\xf9.\x00\xb21\x84&\xaf\x03`+\xd4\xc6\
+i\xa7\xa3\x0d\xe9\x06\xb6\xc1\xdf\xc4\xbb\x00\xd8\x0c\xeab\
+R\xb3\xbd\xc5\x9f\xc6Q\xc3\x1a\x9dM\xbc#\xbf\x0b\x80\
+\xad\xab:e\xadW[\xc5\xad\xf7\x1b\xd6\xfc\xa4\xd7\x85\
+\x0e%\x8d\xfa\x00Xa\x83@\xd4.\x006\xb0\xb1\xd5\
+*\xe8\x02 \x0b\x021\xe6\x10\x00;5\xad\x8f:-\
+\xad7\x1b\xd8\xfa\xbd\xc9w\x01\xb0\xd9\xd4\x05\xc0\xa7]\
+\x0a\xc9\x7f\xbbK\xa1\x9f\x0e\xe9}({\xb1\xbb\x8f]\
+\xdd\x18M\xdf\xbfp\xfc\xfa\xee_\x0a\x01R!\xe4]\
+$:\xca]'\xba_>\x81\x99\xbb$\xd0\x7f\x1d\x04\
+\xb6\xcb\xad\x1d\x13\x88\xe5\xd7\xe7\x81EwI`\xfc\x0a\
+=\xd0vI mK\xe0oIdr\x82\xbb\xec4\
+\x89\xfc*o9\xb9\x14\xde\x96\xc4\xdf\xa6b\x7f\x92\xc4\
+|yO\xdc\xe1z\xfbR\x11\xc24Y\xa6\x99x\xf9\
+\x9e\x9a&Q\xbf\xa5'\xaa\x80\x86\x86sg\x1f\xa1\x01\
+\x87*w\xf6\xb9C&%Zg^\x12\x08[\x84u\
+V\xba\xce<\xee1\xbf\x1c\x84\x10\xc4\xa29,\x9c\x11\
+;Z\xd2\x02\x81D-X\xeb\xb7pT\xa7X\x04\xa8\
+\x9b1\xda\x82\x11(\x94d\x17aU\xcao\xfd\xf0u\
+\xfd\xb0$D0Q\xcd]v\x84\x10\xe5\xb7\x9e\x0d$\
+\xd2\x9d,\xf0\xf4s\x19\xbdM\xdb\xcfe\x90\x83\x16C\
+\xc4\xd4_\xd6\xba\x8e\x17\xc0\x22a\x0b6p)\xb8\x9e\
+i\x0c\x02\x96\xd4RF\xb8`\xc9\xac\xa0\x00G:/\
+\xd8\xc1\xc2M\xacb\x0a\x91\xc4U<\x810\xa2\x8c\xe2\
+\x85 \xd0\x8a\xe4B\x0dPX\xc3\x1aX\x16\xc1\x10j\
+\x8eeC>\x0bx \x17\x1f\xe4- \xcd-xA\
+\xe8`EK-*\x08\xa4\xa2R\xee\xc0\xda&\x12`\
+\xca\xe8\xe5e\xad\xe8NO\xde |\xd7\x1co\x92}\
+\xcb\xc9A\xd5\xc9u\xc1\x0a\x99\x051\x86\xe9/ps\
+&\x1b\xc0B\xe4\x9c\x15T\xb8\x95\xbe\xa3\x8ds$3\
+m!\x04\xe2\xae\xe6#H\xc8J\xba\x905o\x18w\
+\xd2R \x8a\xf1\x8dn\x05v\x22\xd1\x85!(\x16r\
+k -<*\x88\xe4Mw$ )\xea\xc8\x99\x18\
+h\xd6\xcfxo\xe9\x1c\x85\xabnc0\x22\x92[\x8c\
+*\xe6\x02\xc4\xf7\x84C $3\xca\x9d\x96h`\xde\
+\xb5'n\xa5\xfb\x86;\x82\x17\xb2B\x0b\xa9\xd2\xecQ\
+\xa8\xaa.P\x9c\x8a\xf1B\x04\xa2\x14\xc1A\x9a\x80s\
+\x94\xaf\x22\x81\xb7\xf2\x0c\x8ehC\xcc\x090%\x0e\xaf\
+\xa0\x81\x97B\x12\x83\x0b\x9a!\x9bNz\xeb?\xf6\xaa\
+\x17\xab\x8e\xadb\x07\xb1\xdb\xae\xd4\x046M\x8e\x0a\x8f\
+\xad\x22\xa9\xad\x220\xa3\xc8\x0a\x16H&u[\x83C\
++\x8b\x91\x8dS\xe5k\xc4\xed\x16\xf9\xf3\x1a\x91\xe4j\
+\x8e'\xb8\xb9\x10U\x10\x81(4i\x11\x04\x94\x14\xaa\
+Uo\xdc\xb8t0\x98\xder\xa4\x06\xaa\x86\xbc\x08\x81\
+\x82\x99\x92\x15c0\xd3\x92w\xe0 \x8dk\xb7\xec\xa5\
+% \x93\x8d\xe2N\x11W\xd0A}P\xbf\xd9$\xf1\
+\xae\xe5?\xdc \x22\xcd\x96Q0\xd4R\x067-\xac\
+\xca1\xaa\xe0d\xa1\x81\x98\x12\x96j\x15K\x88\x9b1\
+\xb2i\x0a\x02\x99Q\xe1\xa1\xbb\x884nl\xc1\x92\x88\
+>v\x02+\x1aMt\xcb\xe4\xb2\x19\x91O\xcc\xb1\xfe\
+*\x92m\x09p\xf7\xa4\x1d'[\xfe\xe6\xc9\x16sG\
+KoD\xf8 G\x91;0;f\x9f\xa4\xc8\x13$\
+0y3IQ (a\xb1\xcd,EAPH,\
+\xef\x05\xfbLHI\xf6\x96\xa66\xc1\x96\xa6Z\x05}\
+\x9e\x22S(\x99e3M\x11\x07pXx\x97\xa6\x08\
+A\x8c\xf0\x9e|\x11Pv)\xd1R\xd5-\xa8\x18-\
+[\xb5\x0a\xee[@\x02\x16\xa9e3]\x11%D\xa6\
+\xe9f\xba\x22f@\x0c\x91>c\x11\xdb@-Q\xcb\
+X7\xa0ht\x19\xabU\xd0'-\xaarE\xd4[\
+\xd2\xda\x04[\xd2j\x15\xf4\xa9\x87\x84\xc1\x99\x986\xf3\
+\x16i\x01WQ\xdfL\x5c\xe4\x08l\x0f+\x08\x84\x0c\
+\xe2\x96\xba\x1a\xd62W\x13\xbfo\x80\x05$K\xe1\x96\
+\xbc\xd6 \x16\xe5\xdcL^d\x09Jb\xd9g/\xb2\
+\x02!\x9c\xb1\x99\xbd\xc8\x19RH\xbde\xaf\xce\x8f\xfb\
+\xf4EJ\xeb\xa6\xf5\x19\x8c\xd4@2\xc863\x18i\
+\x82\xa7\x12\xb5\x0cv\x03\x0a\x8bti\xac\xc1}.\x1b\
+\xe1@\xeb\x12\x07i\x00k\xe9s\x19\xa9\xae\xfd\xbeO\
+G\xa4\xf5(Bl3\x9b\x91\x14\xf0\x0c\xa1\x96\xcd*\
+\x167n\xdb\xcb\x8b\x01\x92\xa6n\xa63\x12\x01+\x8a\
+\xd1\xb5J\xa4Y\xd0\x0ckp\x97\xd8F\x18\xbd\xd0f\
+b#QPR\xd7\x96\xd9\xd6-\xc8\x9b\xf1\xd45,\
+\x803\xacKm\x83a,(\xd2R[\xd7e]v\
+\xdb\xfe\xee\x81\xff\xfb\xdd=L\xa4\xe9\xdf\xee\x89\x9f>\
+i\x8e\xbbL\xd3s?\x0d\xe3\xa4\xd9jf~;6\
+\xfd\xab/Ny\xe4\x97c\xc2\x19\x9c\x91\xad\xc8\x8c\x11\
+\xf3\xbf\x1dk\xab\xe1L\x80B\xdc\xffZF\x08$\xdc\
+#\xfb_\xd6 \xb8k\x1aw\xab\xe3\x85!+(\xba\
+\xe5\xb3\xc3\xc0\x22\xcc\x5c\x16\x04\x85\x0c\x8b\xd2\x0e\x1e!\
+f\xb6\xed\x1e\xd3V\xdf\xc6\x11fYS\x07\xe6L+\
+\x1dmV*j\x89\xd1\xd1\x16\x90%\x84):\xdaZ\
+\xd9mis\x16\xaf\xb4\xed\x84.,\xdf\x94.\xa2\x00\
+a\xf1\xdc\x82.F\xe0\x94\x0c\x9a\xa6\xeb\xd9\xc6\xbb[\
+le\xbc\x13>\xcf\xf8\xf9\x07Y\x08\xdc\xc8\x89K\xed\
+\xd3_.]\xb63\xba\xe6c\xac\xab\xe5\x8b\xc4XW\
+\xc7Gb,\xa7\xaaR\xc63bl\x9f\x9b\xb6\xf9\x1d\
+V\x14#\xa4\xf5\xaf=\xda\xd1\xb2\x80\x858\xb9\xd7\xaf\
+\x02E\xc2X^\xcf\xa4\xeam\xbb\xb9]T0\x98\x15\
+M\xef/*(\x81\xd4$\xfb\x9fl1\xa0b\x98\xb4\
+\xcb\x87\xc9\xb2\x87\x13e\xa7\xf2vq\xdbj\xb1\xbb\xb8\
+\xca3\x86`S?Q\xed\xcc/\xd1\x8b\xabM\xfd\x8a\
+}n+\x8e\x89\xfdc\xfeX[8\xaf-&\xb4\xd1\
+\xe3\xda\x9c\xa7\xb4\xedj/\x02\xb6\xc89\x96\xd8\x12\xbf\
+\x9e\xa5\x88\xa7\xb1\xc4\x96\xfc\xf5,\x1d\xd2K\xb2\xe4\xaa\
+>\xbf\xab\x85\xe6\x13|i\xfc|=K\xae\x863,\
+m\xa9\x0dw\xc1\xd2\xf6\xc9a\x96F'~\x0a\x8do\
+\x8f\x13\x9f@\xa3\x93\xce\xd08\xabm\xf74\x0a\xcd\xb3\
+$\xf2\x84!\x89\x12\xf8$\x96\xc4\xbe\x9e\xa5\xb7\xc7\xb6\
+\xc2\x17di>\xbc\xfb\x13\xc3\xbb\x9b\xdbSX\xd2x\
+\x8a/\x1dUoz)\x96\xd8\x1c{\x96f\x1ac\xe5\
+\xa1\x83\xccP\xd8\x02\xb7s\xc7\xd2\x9c\xb6<B\xdcJ\
+\x1bMk\xd3\xdd\xf9R\xe8\xbc/\x85\x7f\xbd/\xbd}\
+\xe2\xa5\x82{\xe4S|\x89\xea\xe7\xa5|IXb~\
+C0)O\x19q\xab\xb7\xf9\xf6\xebY\x12V\xfa\xa5\
+%A.\x05\xe7X\xe2R\x9e\x90\xe3\x0e\xc7\xcf\xd7\xb3\
+\xc4\xa5<%\xc7\xd1\xf0\xe7\xa5.\xa8\x04\x99f}\x09\
+\xf9\x099\x0eq\x9b\x11\xf7\xd5U \x90\xb9\xb8\xb8N\
+\x86C\xb0W\x93\x06\x94-\x9c\x18\x85&\xabtfW\
+\xaa<=\xa1\xb1\x9e\xc1\xc1!\xdb\x0c\x22\xe4\x99\xe4\xbe\
+\xbdZ\xf1\xf1O\xcc\xf9\xc9\xf4n\xa7\xd3\xfb\x84\xb2\xa9\
+<o\xdf\xd1\xf9\xfdL\xe7\xf7E\x9d\xdf]u~\x9f\
+\xd6\x99{\xd8\xb9\xed\xc6\xe6'\xf1\x1e\x89J\x1e\xb4\xfd\
+\xec\xc1\xf4\x04S\xdbNH\x08\x828\xd4\xe7f\xae*\
+Z\x12\xc8\x83\xc2\xb6\xda\xb3\x86\x5c\xcdB\xee\xf6\xac)\
+N\xc3\xba\x829\x14B\xe3\xfa\x95 \xc3J`y\xfd\
+\xb3\xd2\x99\xb1\xcb\xcd\xb0R@\x89\xcb\x02\xc1\x15\xd3l\
+~\x1e\xa8\xf5\x11\x13`\xd1R\xb4\xd1\xbeF\x09\xa9\xa2\
+]\x17\x91\x01e!\x91\xae\x8b8\x001\xd2t\xe2\xc9\
+\xcd\xdd1Z?\x8f=\x81\xea\x05w\xb9#\x8d\x9b\x87\
+\x88\xdd8\x12\xb3rY?'\xe0.Y\x16KQ\xa0\
+\xc4(?\xc5\xf4\xc5\xc1Q7\xe1\xa5\x0c\x81(\xc6\xfd\
+\xe4\x18\x0aXb\xa3\xf3x\xb2\xe8qWtbv\xee\
+e]\x19\xf5QW.\xfe\x84\xc8 \x05B\xa9\xdc\xff\
+M%\x09\x98\xa6\x94V\x96'\xcbVtiPX\x8c\
+3\xb6}\x80\xddA\x17\x0cd\xab%\xbf\xe8\xe0\x17.\
+\xf6\x18c\x81\xf2\x04\xc6\x96\x8eP\xd4\xd8\xa8\xa7\x0c\x0d\
+R\xd0\xfa\x81\xba\xb4\x02J\xc6j\x1dgj\xe0B\x8c\
+\xf1s\xc6\xbe@\xdb\xce\xfcg\xacy}\xa6\xd9u\xb6\
+\xf9\xdc\xd3\xd6\xef~^\xba\x9e\x9f*\xe6WV\x1bm\
+D\x06\x0fWu\x83\x00S\x0b\xe6\xcc\x0ap\xb7X\xfc\
+\xb3\xb2Vv\xcb\x9a\x12\x17\x14\x1eR,\x151\xcd\x17\
+\xcb\xb1\x02\xc5\x09\xb5\xa74\x81\xc5\x8a\xfe\xbc\x03\x97\xe8\
+7Nw\xce\xa9\xfc\x828\xb5\x02H\xee%\xeeo\x11\
+\xec\xa8(\xd4q\xea\x02jj\xd8ge\x22\x10+\xa4\
+\x13\x83\x7f\xdb\x15\xcf\xfb\xfb\xda-3\xbb]\xed\xb6\xa2\
+k\x07W6*\xac3[\x01\xb6=\x03g6\x17l\
+\x9b\x10VZ\x9e\xb6\x10<\xb9K\xe2\xd4&\x89K2\
+\xb0~\x93\xc4\x1d\x92&\xaa\xe5\x91\xebp\x15\xa6\x99m\
+'\xfb=*\xfb\x8d,g6\xbb<\xecDg\x5cl\
+\xda\xdf\xb7\x1bG\x5c\x09\xdd%i\xec\xf8\xa8\xa7Q\xce\
+l9\xddmO=\xb3\x81w\xb7\xd9\xf7\x9c\xc3\xcd\x8f\
+\xc3\x92H\x8a\xe5f\x1c\x22h\xc1\xa0]\x913\x7fg\
+\xa7B\xdayT1\x084B\xea<\x8a\x12A\x84T\
+\x7fbS\xd9\xc3I\xc9\xc3N\xf29\x8f\xe90\xee\xd8\
+c\x90\x1f\xf7\x18\xbc\xbf\x8f\xb0\x07%\xf5y/\x13B\
+D\xcb\x83\xed\x89M9{\x87I\x07\xd3\xa0|\x1e\x09\
+\x04\xc9\xee\x14\x0b\x01\xd1t\xe1\xfc\x96\xa3\x08\xa3\xe3\xc4\
+\x09(\x1d\xdd{N\x18\xd8\x8a\x92}+R\x96\x05\xa1\
+X1[,c\xf8&\x5c\xe4\x9b\xb2\xa2\xbd\xa7\x04\x90\
+b\x14\xe9X\x19\x93\x13\x86\xddc\xc5\x14\xd2\xcd\xa2c\
+\x85%\xd7\x06=\x8b\x96\x12\xbb\x1b0\xf37\xdd\x22\xec\
+3{\xdbw\xfb\xe0\xcf\xec\x99\xdf\xed\xaf\xff\xcc<\xf4\
+\xf2\x96\xf3S\x93K\xff\x9e\x84\xfe}\x0a\xf3O\xe9\xb1\
+\xb3>\xe5!<v\xf6\xf9Wd\xec\xfaA\xe7\xe9\xc9\
+-\x9azn\xa7_hy\xd6kV\xda*\x9b\x8fa\
+fN\x19\xd8\xf3^\xb4\xd2\xd41\xce\xab\xa3g\xbcf\
+\xa5W\xc6;[\x1fu\xc2\xe7uI{;\xd0|\x97\
+\xf0s9jo\x07\x9aW\xa6O}\x1b\x0d;\xfa\xfc\
+k\xa2\xfa\xd7J\xcd\xbf\x86\xaa\x7fm\xd5\xd3\x062\xe6\
+v/\x95z\xf9\x81\x8c\xcf\xf3\x9a\xf6&\xb2\xf9\x8e\xc4\
+gy\xcd\xfc\x9b\xc8ze\xba\xb3\x91eE\x9f\xc9\xd1\
+q\xfdl\xc5\x91\x15\x7f\x02G\xf3\xcapZY\xee\x8e\
+\xa3\xccgr\xe4\xb2*[r\x84\xdf\x92#\xde!G\
+\xfc\xdc\x08=~\xb6\xe1(\xf5\x99\x1c5e\xf3\x1c\xa5\
+\xef\xf0\xb9\x04\xcd\xdf\x9eJx\xe6\xbd\x0d{\xd8N_\
+x#\xc2\xac\xe3\xb4G;Z\x122\xa0E\xf1\xc52\
+\x14L\xc2\xc5^O\xdd\x10\xcd\xdd<\xf57Z\xd37\
+e?/\x9b\xf9\xe2l\x92\x80X\xbaK\xc5\xb4\x04\x15\
+\xa3\xd7\x93\xb7\xdc3w\xe7\xdd\x9d\xfc\xf4]\xff\xcbR\
+\x89\xfc(\x95I/O%\x81fQ\x1d\x5c\x14\x0a\x17\
+\x13\x7f\x06\x97\xfdLQ?\xa9\xf4\xf3>\xd8\x91/8\
+\xc6Q\x10\x91\x17\xcbR\x00\xb9Hz\xe5\x92\xc1]\x0b\
+\xf9\xeb\xe9Y\xc2\x86\xce\xcfEN\xcf[\xf63\x94?\
+\xeb\x88\xcf\x9d\xae\x92\x92A)\xe18\xbe\xbdI\xa5\xa0\
+\x95\xb9\xd5\xa7\x17zA\xe5\x8b9\xec\xfc\x0a\x08{\xe1\
+-I\xdd\xe5\xa2\x0f\x0b\x98R\xaa/\xb4\x80\x93\x9b4\
+\x07\xde\xf6\x8db\xdb\xbfC\xac_\xb5\xf9y\x1f?z\
+rx\x98_y,\x0e\x88,\xc5o\x9e\x1bd\xb5\xa8\
+\xac\xee\xf8\xcdb?\xe7\xb3H^b\xf7o\xe5|\xa9\
+\xb7\x90\xaey\xfan\xffhu|5~\x1b\xb76j\
+\xfb\x17\xa5\x01\x93\x8b\x8d\xb91\xd8%\xa3\xeeaB\x01\
+\xa6\xc5T\x17\x8e\x10\x98\xc1\xc3\xbb\x1a\xc8\xc1\xdc\x19+\
+J\xa0$\xa5\xc8^\x8b_\xce\xa0\x96%c\x13\x93*\
+\x81Ei\x90n\xa8\x82;g\xb1\xcd\x1a\x0d\x02#\xb3\
+l\xea\xf6A\x0b\xd9\xd0\xa2\xac\xd2(9\xb6\xd3@\xd2\
+\xc7\x16\x15\x04T/1\xa0\x09H\xee\xbaWn\xf5\x8c\
+\x98d\x11\xef0^7\xa9\xd6\xb9\x81\xda\x0d\xf8\xe7\xae\
+(\xb8\x97D\xdd\xcb\x84\x12\x81\xa9\x8b\x02\x88\xe1\xea9\
+I\x5c\xddc\xa5\xdb0\xaa\xa2\xa5B\x93[\xae<\x1c\
+\x93\x0f\xb6\x5c\x19\x0f/?\x9e\xae\xde\xac~\x5c\x9d\x9d\
+\x1f\x1dmn\xc2R{\xf6\xb7\xfe\xfc\xe6\xfd\xa9\xd4\xf7\
+g{\x0e\x9fM=\xc9u\xe2\xfd\x22-\xc9\xed\xa6\x8b\
+\x13\xf4\xc6\x22\x04g\xd1\xb1;2@\x19\x8d\xd6hf\
+0\xed\xa5\x83\xa4\xc4\xdavDd\x8ej\xe7\x9d4\xdd\
+v\xe6\x0f\x83t\x06\x8fh\x01J\xabhO\xa8\x03r\
+\xf1B\x934S\xcf3\x83+[\x96\xbd\xc2\x80\x96\x9e\
+c\x9b\x14\xc3\x91&[\xff\xc3\x14:\xc5\xbel;\x9a\
+\xb2|\x1d\xd5\x7f\x5cO\x91\xae+[\x7f\x17\xc9x\xfd\
+\x13]\x10\x0c6r\xbav\xdb P\xe6B<`\xc4\
+\x11\xb9\x17\x08\x92\x8e\xa5\x0c\x90J\xe1\xf4=/\x83\x14\
+WscL\x8d\x03\xd7\xce6\x98\x8f\x03\xc3\xea\x19w\
+G\xb5\xda\xe1_\x01Lr\xad\x15:\xa0\x13F\x19\x18\
+Ju\xf7\xbe\x15?t\x87w\xe4]O\x5c\x1f\xa5\x90\
++\xf1\x98\xb9\x97\xe3V]\xea.c\xcf%\x88\x1a\x96\
+\xd7\x0f\xa9\xb7\x9fr\xfc@%*\x19\x1b\x8e\xffp5\
+\xedE{#\x1d\xc2\x8c}\xed\x90\xa4\xe8^\xe9`\x02\
+&w\xb4!\xba\xb9`\xa6\x0cQ\xab@\x94\xd4\xac\xa8\
+\x00j\x96\x12{\x8c\x80l\x9a9D2.\x1c\xca\x83\
+4\x11E\xf8\x10\xc9$\x0a\x0a\xad\xa3\x16y\xfa\xa0\x89\
+\x10\x84s\x0c1Y\x80\x9d\x8a\x0d\xa8\x80\xa6\xa1\xed\x15\
+\x011c]cn\xa2\xd4\xb0\x0d\xe9\x1f6\xd1\x00O\
+\xe3\x18\x87SC\x152\xa4\x0c\xb1\x918s@\x04\xcc\
+]\xb8LY>5lbb\xd8LF\xa8\xdcM\x12\
+\xe2H0C\xd5\x05\x13\xa8\xebh'\x93\x02\xa1i,\
+B \xd1\x8b\x95j'\x13CP\xf1\x8a\x1a(\xb9!\
+\x8dXQ\xb2E8$'I\x8c\xc2\x88\x82\xeb\xed\xf5\
+\x9c\xd0i\xa82bA\x5c\x00#\xdd\x87\xca\x92*9\
+\x0c\xee\x98\xf5\xc0\xc6\x834\xca2\x1e\xb5\xa2?\x8c\xc7\
+,P\xb8\xb0p\x15\x1d\x8f\x11BRl(M\x90\x1a\
+$\xc3\x10eSN\x994j\x02l#o\xe6V\x1a\
+!\x93\xd0=\xeb\x18,\x09Z\xca0-!\xe0\xc8\xae\
+\xa6\x13Cp\xe2Zbs\x87\xb4\xe9HX\xe2\xf5\xbd\
+\xfd\xda\x00#\x02K\xbc\xe8\x9b\xab\x9a\x07M\x0dfz\
+d0\x17\x88\x10\xa7\xd1\xf1\x1d\xc5(\x87!\x96\x90\xca\
+\x98k\x94KJ\x8e9\x8b)m\xc4\xb2 \x9b\x8f\x03\
+\xc2os\x93\x96,l\xb7\xa1\x80\x10c\x0c\x05\xaa\x12\
+|\x1b\x0a83\xc7P\xe0\xacY\xd6\xa1 #u\x1d\
+\x0a\x8ac\xacC\x81a\x8c\x91 -\xd7\x1d\xcf`\xa6\
+D9^\xd5`a\x8aZ\xa58\xa4\x92\x86,\xbc@\
+h\x18\xe6\x9e1\x84\x8f\xf7FA\xe0L\xe1\xebL\xe0\
+\x5c\x8a6\xacJG@\x88\x16\xcd\x0d4\x0d<]q\
+,IQ\x10\xcbFl\x08\x04Qv\x92.\x8e\xa8\x00\
+\x16w\x93\x07\xd1%D\xd3\xfa\xe8b\x10\x8a\xee\xb1W\
+\x08\x92\xb9\xc4H\xa7\xa99O\xf5\xc5\xc3\xf0\xa2\x8c[\
+gezl[\xc1m\x1c\xc2\x82L\xca}\x87\xb0\x12\
+iv\xcf!,9\xf2\x9eC\xb8\x17\xf5\x07\x0eA,\
+c\x1cg\x04\xc1\x22\xa5,\x9c\xc1H\x07\x00\xd3\xad\xd0\
+\xe0!\xa2\x12\x98c!2\xc7\x8a)\x10z(\xafE\
+U\xdc\xc8\x87\x92\xae\xea6J\x07*\x8a\x0c\x18){\
+\xe1M\xc5\x0c.\x16T\x9b\xb3\xd9H\x07-\xc8>\x9a\
+\xd8\xcc1\xc8$oF\x0f\x883Qd\xa3g\xc0\xac\
+h:U\xd9\xd6\x99\x03*^\x9c7;\xdd!\x84\x91\
+6\xa1\x04wM.\x0f|F\xc9\xd0\x1f\xf8\x0c\xa6\xe7\
+}\x9f!q\xa5\xa9\xfez\xe04\x82\xea\xdb:M\xe4\
+\x13\x9c\xa6\x10H\xb0\xd9\xdas\xc5\xb4\xf8\x9a\x95\x12%\
+\xd6\x8c\x92\x07\xa5\xef\x15\x06\x11*4bE4T6\
+1\x87\x0cE\x1a\xa2HC\x95\x81KP\xf2v\x03\xac\
+0\xa9\x8dd\x93\xa8\xae]6\x0aI\xe1\xc9v\xfe0\
+\x85\x8e{\xb12C\x86\x14\x1c/J\xb2\x84\xd9\xe8\xcc\
+\x02\x16\xa1J}(\x0aH\xd7(](\x12\x88\x94H\
+\xdb\x080\x81`\xe9B\xde\x87\xa2\x04CB\xe2\x0d4\
+\x1d0L}\x1d\x8a\x0a\xabQ\x1f\x8a\x14\xdd\xa2\xa3\xc4\
+\x0b(\x19\xf3\xd0\xa04\x90 \xb6\xb1\xa8\xb0\x15.C\
+\xc4\xc3\x08\xcc\x1c\xb0d\xe6b{\x9e`R<\xa8a\
+U\xda\x18\xd8\xccs\x13\x15\x87\xa4`-\x83\x1eT\xcd\
+\xe0i\x8a\xa6\xd0\x09\x9f4\xdd\xda'm\xd6'\xbf\xdb\
+\xbf\xfa\xf1\xdd\x9f~\xf7_\xea_?\x7f\x00\x9a\x00\x00\
+\
+\x00\x00\x15,\
+\x1f\
+\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xed=ko\xe3F\x92\
+\xdf\xe7W\xf0\x9c/1N\xa4\xfa\xfd\xf0xf\x81\xdd\
+A\x82\x00\x17\x1c\xb0\x9b`\xf7[@K\x94\xad\x8b,\
+\x1a\x92<\x96\xe7\xd7_U\xf3\xd5$[\x14\xe5\x91'\
+A`;\x89\xa9\xea\xeaWu\xbdY\xad\x5c\xffm\x7f\
+\xbf\x8a>g\x9b\xed2_\x7f\xb8\xa0\x09\xb9\x88\xb2\xf5\
+,\x9f/\xd7\xb7\x1f.~\xfd\xe5\x87\xd8\x5cD\xdb]\
+\xba\x9e\xa7\xab|\x9d}\xb8X\xe7\x17\x7f\xfb\xf8\xee\xfa\
+\xbf\xe28\xfa\xc7&Kw\xd9<zZ\xee\xee\xa2\x9f\
+\xd6\xbfog\xe9C\x16}\x7f\xb7\xdb=\x5cM\xa7O\
+OO\xc9\xb2\x04&\xf9\xe6vz\x19\xc5\xf1\xc7w\xef\
+\xae\xb7\x9fo\xdfEQ\x04\xf3\xae\xb7W\xf3\xd9\x87\x8b\
+\xb2\xc3\xc3\xe3f\xe5\x10\xe7\xb3i\xb6\xca\xee\xb3\xf5n\
+;\xa5\x09\x9d^4\xe8\xb3\x06}\x86\xb3/?g\xb3\
+\xfc\xfe>_o]\xcf\xf5\xf6;\x0fy3_\xd4\xd8\
+\xb8\x9a'\xee\x90\xa8\xb5vJ\xd8\x94\xb1\x180\xe2\xed\
+\xf3z\x97\xee\xe3vWXc\xa8+#\x84L\xa1\xad\
+\xc1\x1c\x87u\xb5_\x01)\x0e.\xc6\xb5\xfa\xb3\x03\xf9\
+\x1f\xe0\xdf\xbaC\x05H\xb6\xf9\xe3f\x96-\xa0g\x96\
+\xac\xb3\xdd\xf4\xd3/\x9f\xea\xc6\x98$\xf3\xdd\xdc\x1b\xa6\
+\xa2~k\xde\xd6\x91\xac\xd3\xfbl\xfb\x90\xce\xb2\xed\xb4\
+\x82\xbb\xfeO\xcb\xf9\xee\x0e\xb8\x81\x19\xf7\xf1.[\xde\
+\xde\xed\x9a\xcf\xcb\xf9\x87\x0b\xd8\x1f\x17\xa4\xf8\x5c\xad\xe0\
+\xaa\xe6#\x92pV\xa0\x96\xc3\xfaM\xc2$4\xdaX\
+\xad\x88Ci1_k\xb8y>\xc3\x15~\xb8xH\
+o\xb3\xf8K\x9e\xdf'0\xed\x97\xf6\xc0\xf9\xe3\xee\xe1\
+q\xf7[\xb6\xdfe\xebb\x1c\xd8\x99\xb7M\xd7\xec\xfa\
+%\xad=\xd6\x03d\xfb\x87|\xb3\x8b\x17\xcbUV\xcc\
+6\xbd\xcb\xef\xb3\xe9\xc3r\x0d\xfb\xde\xe4\xf00\xdbN\
+\xf3\xfd\xf3m\xb6\x8e\x973`\xb5)\xf4[\xa57\xab\
+l\x9a\xcevK\x07\xb8OW\xab\xa90{a\xa6\xdb\
+u\xfa\x10\xc3\x80y\xf2\xb0\xbe\x0d\xce\xb4\x9f?\xc0\xd1\
+R.\x83\xad\xcfu\xebGh\xbe\x9eg\x8b-\xa2\x15\
+T\xc7O\x5cP\xe2\xda\xa0\x15\x18'K7?n\xd2\
+\xf9\x12\xc4\xa5\xc0\xf3\x86\x9c\xe5\xabU6\x83\x93KW\
+O\xe9\xf3\xf6\xa2F\x80\xa1\xda]\xb9\xa5\xaa\x1c\x14\x86\
+\xdd\xee\xf2\x87\x0a\x17\xcec\xf7\xbc\x02\xb2 0\x86\x11\
+\xf3\xcd\xd5w\xf4\x86I\xce\xdf;P\x0e\x0c\xb4\xdc=\
+_\xd1\xf7\x17M\x9f|\xb1\xd8f01\xf1`\x8em\
+\xa0\x07\xcc\x05Je\xfau\xb3\x91\xd0l48\x1b#\
+\xf5l\xd7\xd3\xf6\xb6\xbf\x8e\x8cNn\xaf\xee6\x19\xe8\
+\x99\xef\xfe\xf3\xf3\xff\xfc\xf4\xe97\xfb[\xac\x06\xc8\xcc\
+\x0c5\xa2n\xbf-\xa1\xbf\xae\x97;\xd0$\x8f\xdbl\
+\xf3/\x94\xc6\xff]\xff\xba\xcdzX\xbfl\xd2\xf5\x16\
+D\xff\xfe\xc3\xc5\x0e\x1fW\xa0|\xbfg6\xb1\x8a+\
+i'1\xb0L\xa2\x14\x93\x97\xcd\xfa(\x90DX\x90\
+E\xab\x1a\xd2<\x03\xd4\xc8\x84s!H\xb3\x96=\x03\
+\x5c)p\x04\xe3\xe12\x1f\xb7\xa6\xe2\x01z\xc1v\x03\
+T\x18\xb7K\x5c\xab\x15\x09\x17\xdc\x10\xdeZ+%\x0c\
+\xc0B\xb7\x96jT\x22\xb9\x94\xd6\xb6\x96\x0a\x03H$\
+\x869\xc4\xca!\xb6\x0c0\x9c\x9c\xe1\xef\x00{W\xcc\
+\xa5X,\x0f\xb3r\x85\xa5\x85f\xf1\x91)\xb3\xc5\x82\
+d\x8b1\x12\x95p\xca\xadPz\xdc\xc4$\xa6\xc3\x13\
+\xa7iz\x93\xdaQ\x13k\x06ZB){x\xe2\x90\
+ \x86\xe8\x0bG'\xe9\x18\xfa\x0a\x8f\xbe\x7f\x06\xe1=\
+\x95\xad\x03\xc2{\x9f\xee6\xcb\xfd\xf74\xb1\xf8c\xe8\
+\x84\xc0\xaf*>Y\x09r\xccXB8cz\x12+\
+NA -\xb3\xdf@\xa6q\xa1\xe9\xeaU\xc8\xd8\x1e\
+\x1a\xc9h\xceFF\xa0\x95\xfb1\x8e\x8c\xe5'\x0aT\
+\x14\x0a\xf6\xcd)>R\x0d\xbb\xe5\xba!\xe2l\x8fD\
+D\x04\xe6i\x90\xd93\xba8\x04\x87\xa0\x0dt\x11\xc4\
+]\x04q7\x1f.\x90\xb0\xe0\xfb\x1cS\x95'\x91\xb5\
+=\x86\x16\x96\x0ds\xa9%_O\xde\x03&\xc6 \xe3\
+Q\xde\xe5G\x9dP\xaa\xba\xdc\xa8\x8d\xe6\xa6\xcb\x8d&\
+\xd1\xd2\x18\xde\xe2F\x0aS0nGX\x98\xd3\x1d\x1b\
+G\xad\xf1\xae\xc6\xc2\xfd\xbc\xd0\xb1\x81\xb9\xc4I\x8eM\
+h\xb6\xd1\x8e\x0d\xcc\xa6\x8e\xe9\xc6s\x08u\x87\x9e\x94\
+\x9aa\xe1\xf6\xb8s\x1c\xf7\xa14\x1a\x9d\xc8\x96 \x82\
+3c\xb4$\x9e6CA461\x82\x1a.[\x82\
+\x08\xeaPjmmK\x10)\xa0j\xc6H\x7f5}\
+%B@\xfbRI\xb8\x14\x13\x88\xa2('\xe0n\x10\
+>)\x1fQ\xb7 \x82\x90\x0a\xb4\x09O,W\x94q\
+>\xa1\x14,\x22\x01\xddz9\xc63\x0a\x90q<\xa3\
+\xcc\xf9b6\x8aQ\x82lI=\x0f\xf8\xb0\xafPE\
+w\x9d\x01\x13)A\x8b\x12O\x90\x83+\xbcI\x17r\
+\xd1q\x99H\xc2\x80\x8e \xee\xec\xfd\xa8\xf9Up~\
+-\xa5b\xd4;\xc7\xe0\xfc\x86\xdf\xc8\xec\xa6;\xbf\xb0\
+\xe0MZ64\x7f\xd0=\xd1\x8b\x99\xea\x8e\xa5\x8d\x10\
+\x86i3Z>\xc1\x90\xff\x01\xf2\x09+\x1c\x90O\xcd\
+\xbc\x83tfP\x83\xee\x06\xcbF[\xd2'X\xa2\xa4\
+\x96\xac%|}\xd4E\x08\x15d\x8f\xb3DR\xa6U\
+?\xd4\x09\xf9A\x1a\xf8\x8b\x17\xe2f9\x08\x86\xd0N\
+\x0a-D\x02 r\x13\x87`\x15\xe3\xe8\x1aQ0\x14\
+\xda\xc0\xa3\x92\xc0\x98`\xd9/G*\x9bW\xb0,H\
+\xe9\xf1LU\xb8)/\xb5,\xcc\x0c\x88\xf0\xc8\xd9\xc6\
+[\x16f\x8er\xeeb\xb9\xdae\x9b\x9agp\xd6x\
+\xb9\x06\xd0C\x0e^\xc32_\xc7\x05\x06\x9c\xc4\xf6\x9f\
+?\xfe\xfd\xe2$B\x17]a\x19^Nb\x91\xfd\x98\
+>n\xb7\xcbt\xfd\xf7\xd5\xe3\xc6[\xf4\xb1\x01\x91>\
+\xf3O\xd9\xe7\xa5[\x16j\x14\xa54\xea_\xdd\xd9z\
+{\x06\x98\xddxD(\x96\xf4jb\x0bq\xaf\x8a\xb9\
+\x17$\x06DW\x04l\xd9\x8b\xa3\x0f\xe7.S\xf4_\
+\x85!\x0a\x9eA\xe4\xc0\x00\x1a\x10.\xd1q\x94-8\
+\x80V\xd3\xb6\xa3lUb\x94\x91T\xb6UD\x0fw\
+\x11\xc4m\xe9\x88\xf3\x8bfM\xcdo\xe4\xf8a\xd6\x22\
+\x96\xf1@`|n\xe7\x0f\x837\x98\xf1hf\xeb[\
+\x88\xa9\xa0\xaf!\xa6\x10\xca\x19\xcb\x055\xc3R*\xe8\
+A)=_b\x80\x92\xdfb3\xc0o\xe8\xf5\x9e\x9a\
+\xd6s\x81\x13X1%\x8c'\x18\x18:q\x9epb\
+\x98\xe7\xe4\xba\xd0\xc9\x9a\x84\x1aF<\x5c\xe6\x1cb%\
+\x8d\x1a\x9f\x9ako\xe5\x84\xdc\x5c{\x8d\xd4K\xd2U\
+\xf98\xa3\xa4\xa7\xa1\xaa|\x5c\x01\xfd\xba|\xdc\x0f\xee\
+'\x94\x1f\xb2\xb1\xfa\xfal\x94\x04\xff\x85\x07F\xd7\xf4\
+x\xf6\xe9\x8f1\x05\xec\xe4 \xeb<\xa6\xe0u\x9d\xc5\
+\xd7L\x9a\x10A\xbdLhX\x84OM\xeem\x1f6\
+Y:\xff9\xdb\xdd\xe5xD\xd9\x02W\xd5\x16p\xc3\
+\x13E\x88l\xe7F\x804\x84C\x10\xd9\x16p\x10\xed\
+\x84\xa3\xe7\xe5K\x10x\xc3\xe8\xae\xbc \xc0,6\xfc\
+\xad2\x1fD\xf0x \xf7\xe1\xe1\xd9X\x86\x06Mh\
+\x91\x00U\xc3\xb2z\xc0h~\xbb\xa4\x0b\x84$@\xd6\
+?\x81\xd5eZ\xbc\x8asL-\xa3\x82(\xd6\xd9|\
+\xd79\xd6\xea\xcf\xe5\x1cs{\xbe\x9c\xf2\x9f\xd29\xfe\
+&\x9e\x1c{%\x9e\x92BA<e\x87yJ\xb0\x83\
+<u~\x83\x10\xe4\xa96\x8a\x12\xe2\x0c\xefj\xeb4\
+\x07a`\x098\xe6\x12\xc1 \x80y4\xca\xb1\x15\x91\
+\x9c0m\x90\xdd$\xd1R\xc9I,T\xc2\x158\xb6\
+\x98qg\x98p\x07\x93\xd9\xc9\xb8\x13\x9aHNE\xcb\
+\xacP\x93(0\x22\x9a\xb6\xccJ\x1f\x15\x80\x12P)\
+\x0c\xcb\xce\xfb\xfe\xa7c\x828e\x83\x22\xeb\xf9\xf6(\
+K\x1a_\x89\x81\x19n\xcb\x92@\x1a1FhK\x96\
+\xfa\xb8\x8b n\xf3Ff\xdcA\xbeB\x9a\x08\xa9\xf0\
+\xad\xcc0\x9e\xf3\xb7\xb3\x85\x9c\xfe\x11/ \x8eq\x15\
+{\xc9\xfb\x87\xd7\xe5\xbd\x93\xbd7n\xac\x8eu\xcc\x0f\
+1N\x9d\x060\xd6\xc6\xa2\xf5\x8a\x7fdH\xb5\x98\xe1\
+o\x87\xcfN\xe3\x1d\x83\xbf\xdd\x11B\xae\x9dd\x0c\x02\
+,\xdd\x8d\xe4\x8b\xea\x1c\x02AV\xac\x8f\xbb\x8e\x80\xc9\
+cv\xc0y\xd4\x8cs\xad\xa5=\xb2g\x92-\x025\
+\x16c\xa6\x96.\xbd\x13\x9a\xdaX\xc2\x84\x1f\xe7\x84\xcb\
+;xF\xb3~\xc5\xc3\x98\xa95\x1cp\xe8\xcd\xc8\x91\
+\x19g\xd9\xecfvs\xe8\x80O\xab\xa5\xe8GK\x1c\
+\xb8\xff\xc8\xd2\x99 /\xe0Kb\x95y\xc9\x19\xc1l\
+\xfct\x22\xa5\xd9l\xd1\x93\x82\xf7\xe7\xa2\x92\x90\xd4\x80\
+\x8f\xa1\x8fQJHFb\x1af\xed#l\x95ep\
+\xce_%\xc5\x02\x7f\xc7H\xb1(\xde)\x84,\x81\xb4\
+\x0a\xd5\x10?~L\xb0U\x16\xdb8\xf4\xa6\xf1\xc8Q\
+-\xd4B.\xe4y\xf8\xf9k\xfcFK\x87j\x84\xf0\
+ec\xcbSS\x1c\x8d\x85\x9f\xbaw)>\xacH\x91\
+\xca\x83\xa2\xab\x16\xc0eE\xceD\x8d\xae\x98y\xc5\x1c\
+\xca\xd1\xad{\x19\xcb\xf1\x89\xc5\xd7#\xd0\xa1\xc0\x0e_\
+\x0b\xbb\xd2+\x81Q\x9e\xc1\xfc\x8a!\xfa\xf8K\xfcW\
+%\x9d=\x91tC\xc5\x0c\x8c\x13\xad\x80\x11\xbb\xbb\x8d\
+\xa5L\xa8\xa1\xd0:aHI\xd8\xb6\xb9|\xa5\xc3\xf8\
+#\x89)\xf8k\x11\x93\x96\xd5f-Zb\xda\x0e(\
+a\xe8_\x92\x96\xfa\x9b\xd22.\x13\x9e\xe4/IL\
+I_]\xcay\x8b\x9aVb])\xb5\xafK\xcc\xeb\
+)\xdeKpO\xf5\xdd\x0d\xbcJ1\xff\xbc\xcc\x9e\xde\
+\xd5\xd4\xb8I\xeb\x9d\xe1\x85\x0eg\xd7\x81\x86E\x0cZ\
+6\xdc\xe4\x9by\xb6\xa9\x9a\x94\xfbi5\x95\xa6\xbf\xb9\
+-\xe2\x1d\x19\x8eZ\xb7\x93p\xfb\xf6.\x9d\xe7O\x1f\
+.X\xb7\x11\xaf\x97`\xc0\xa6\xa42R\xf4\x9a]\x90\
+\xc8\x13\xad\x89\xe5\xa6\xd7\x88\xeb!\x22\xa1\xa4\xb1Cu\
+\xe3<\x9f=\xe2e\xa6\xf8\xb18\xea\x87}\xaf\xfb\xe3\
+f\x83\x08\xab\xf49\xdb\xb4\xaf\xd64\x97o\x8c\xa9;\
+\x96\xd7s<\xc8\xf6.\x7f*\xe8\x83\x95\x9b\x8fYw\
+\x06l\xf7w\xef\xe1`\xd3\xed\x06\xcf'\xd4\xf1i\xb9\
+\x86\x0equ!\x88\xca\x1eaJ\x8cj\x99\xba\xae/\
+\xeab\x00\x01\x03t-\x1b\x9f\xf1\x15\xa2\xbf\xa2\xc7\xe5\
+<\xdb\x86\xd7\xe4\xda\xe2\x9b\x9b|\x1fn\xcfo\xfe\x0f\
+\x047~Hww0\xc2\x22]m\x0f\xa1\xacs7\
+\x89\x8fR\xb4\xec\xf2U\x06\x227\xcb\x1a\xb7\x14i\xe4\
+\x83M\x8b-\xcb\xa3\x0b\xd2\x1e/\x04\xdd\xae\xf2\x9bt\
+5H\xe3\xfbt\xbf\xbc_~\xc9\xe6\x8d\xd7\xdf\x1e\xc3\
+\xdbq\xa9\xc2\x1a\x92\xc0\xe2*\xf9\xdc=\xe3\x95\xaf\xfd\
+3\xc2Z\xda\x08\x01L\x88\xc6I\xc3\xab_\xcb\xf5\xed\
+\x1e_\xb6\xa3\xa0\xd5\xecT7=\x07\x9a\xb2\xfb\x87\xb2\
+\xb5\x91\xa2(\xfa\xbc\xdc.o\xd0g\xf7v\x08\xb8k\
+\xbc'5\xef@q7%>\xae\x09\xb5\xe46_\xaf\
+\x9eK\xb4J\xa9\xf4u\x89\x83\xdfg\xbbt\x9e\xee\xd2\
+F\xb1T\x10.h\x951\xb9\xde\xcc\x17W\xff\xfc\xf4\
+C\x1d\x8e\xccfW\xff\xce7\xbf7!\x06\x22\xa47\
+\xf9#\xf0l\x1d\x9f\xe1}\xab\xd9\x15\xea\xd9t\xf7q\
+y\x0f\x02\x83\xf7\xf8\xfe{\x7f\xbf\x02\x15W7\xb4\x90\
+\x91\xda\xcd\xa0\xc5\xb0\x9b\xac\xb8\xa7\x17\xbc\xda8\x9f\xdd\
+/\xb1\xd3\xf4_\xbb\xe5j\xf5\x13N\xe2\x85M\xe5\xa0\
+\xcb\xdd*\xfb\xe8\xe6,\x1e\xab]L\xcbmTA\x8f\
+\xb7\xcb\xebiE\x06\xf7\xe9\xb6!\xcf\xadVu\x22{\
+\x17\xaa\xf06\xa0\xd6\xa4\x92LMb\xbcz\x90\xc5\xea\
+\xb2\x22\xe3m\xcdU\x01\x0b\xc4\x85`\x8a\xa1\x01\xa7\x09\
+3`\xb3\xb1X\x8fY\xc9a\xc2\x89k\x96V\x13\xbc\
+\xd2@t\x02\xce&\x07\xbfS\xf2D\x12a\xd9e\x9b\
+5\xb1\xd4\xb7\x09\x937 \x82\xbd`\xb0\xa9\xc4\xb4\x9a\
+\x12\x0a\x91\xe4\xfb\x05P\xf0\x0ah\xfb}\xc7\x10\xbbk\
+V\x97\xae\xd9\x0b\xeb\xb7\xbbM\xfe{v\xb5\xce\xd7\x0d\
++\x96)D\x98O\x0b\xe5\x07\xdb\xa5\xc6\xeb$\x8f\x1b\
+u\x8c\xf5\x0e\xae,\xd1ks\xaf\xbd-P\x80\xb7J\
+Y\x81\xafc)\x12\x10=\xdd\x1a*DRM`o\
+\x10\x8fL\xbc\xc78\x0c\x06\xa3\x7f\xe9\x07\xdcm\xa2\xe1\
+\xa4B\x83\xec\xd2Vi\x83[\xa2J\x14k\xec\xaa\xbf\
++\xeen\xa5\xb0V*\xa5\xd2\xfdX7\xa7x\xef%\
+NA;\x1d(\x0f\x1e:\x1d5\xf2t\xceL#\xb4\
+\x09\xde:+\x05S\xa8\xcct3\x1b\xdaD\xaf\xd0\xdd\
+\x98\x13X\x0cg\xd6\xc2\xb4\xf29\xd5\xf4\xeeE\xa2D\
+\xd2\xb7\xd8\xa9iw\x97M\x9c\x226\xa1\xf6\xcd>\xc0\
+\xa8M\xebs\xa0\x15\xb5fD\xa5\xc6\xd0EL\xaa\xc1\
+\xa3Y\x84wh\xac\x90BF\xa0\x0b\xb8\x01\xc50)\
+:Gq\xf1\xb7\xfeX\xe0\x81\xa0\xd7-U\x8f\x06P\
+\xe2\xc21\xd4\xff\xae\xa2\xb2\x91D_B\xcb\xdd\xee\xd2\
+M7\xf1U\xb5ekX7O\xa8\xa0\xd22}>\
+6\xa1\xd4\x82\xefF,x\xcc \x1c\x9aI+\xed\x80\
+l\xbdH!Yr\xb2B\xb2\x01\x85\xe4\x0eJ\x9a\x83\
+\xb2\xeb\xbf\x96\x18\xd4H\x01\xe5pNa\xbb\x9e\xde\x96\
+\x0f\xbe\xcc\xf5g\xa0\x89\xd4\x960\xa5'\x18\xd1X\xc6\
+\x85b8A\xfd\xdc \xc4\xb0\x13\x89\xaf-\xc1\xe0p\
+\x99H\xce\x98\x97\xbe(8\x1a\x0c\x0d\xd7\x10\x13\xd5\xd7\
+G\x1cKS<\x22\x09\xa1e\x14\x9b\xc4\x80M2`\
+\xa9\xaa\xfb!Q\x5c>\xb6@U\x0fd\xef\x1a>\xa9\
+\xba\x9b\x16\xb0\xe9G&M\xcf\xa8\xc2\xf5\x11\x82\xbd\xfc\
+\xc9\xaa\xb5\xd4\x13\xf5\x17\xd7\x88MK\xc6\xfb\x17^Z\
+\x0ab\xa09|\xdf\xa6\xa5\x9eZ\xf7sj}\xe6_\
+\xfa:\xae/\xc1\xe8\x8f\x91\x80\x80V\xae\x99j\xc0\x1d\
+\x81xPIK\x84\xbbG\xa0(\xb8\x18\xcaqj\xfd\
+\xdc \xc4\x94\xe3=\x02\xc5\xc05Q*1\x10*\x8b\
+\x9eCB\x14V*\x8d\xb3\x1cM\x5c\xe1r\xd9\xbe0\
+W-H\x86G\x885b|\x1d&\xc0\x15b\x22\x84\
+\x96o\x96\xb7\xcb5F\x0a?G\x10\xc4\xe3}h\xd0\
+\xa7\xael\x0e\x96\x1b\xfd#\xa2\x10\x90+\x108\xd3\x00\
+\xdduP\x87'Ub\x0d\x07y\xf1`Z4}k\
+\xa0\xc5\xb2\x02c\x19\xf5\xc6\x03!\xae\x06\xac'n`\
+\xd0\xdb\xda\x04\x5c<\xc1<(\xa3<\xe1\x94\xf9\x03\xd6\
+ o\xe2\x1a\xe6-\xb0\x1e\xad\xd9G\x7f\xbf_\xa2\x16\
+\x19d\xf9\x80\x8b\x01\x86\x84\xe7\x06\xc6\xd0Aq\x9d\xa4\
+I\x84T\x1c$\xa5\x81\xb5\x16S\x01-I\x0c*\x14\
+\xd3\x0c\x07Q|k\xfb\xc2\x91\x5c\x82\xc9\xe1\xa6h\x94\
+\xcc\xef\x07\x9f|\x02\xc3\xc7f\xf6\xba_\xbd\xc6\xc0V\
+\xbeD\xe3}\x0e\xbc\xbc3$B\xef\x8b\x9a\x99\xa2k\
+s\x87\xe22\xe4\x8a`\x01W\xd7\x1d\xa8V7\x11`\
+cA\x1b\x80\xee\x8c\xf1\xee\xac\xb1\x85\x99\x07\xa9\x11\x0a\
+\xe0\x13*\x12\xa2-'\xca\x83U\x0f\xa8n\xcb>@\
+\xad\x02\x916\xad}|o\x06\x84\xe1\xfc\xb1\xebg\x14\
+\xa8\xbf\x1a\xe4\x8d\xef\x16e\x09Q\xa8\xa8\x01\xd3\x15i\
+5\x08q\xbf\xcf\x97\xe8\x1e\xd7\x95\xe01\xcd\xe0`\x12\
+\xbc\xc9\x05\x9a\x22bx\xa1\x10q\x91C\x15%\xc8\xd3\
+\x15\xa8z\xc0\x9eE\x0fh\x8d\x1d\x22\xe1E3\xce\xd6\
+\xc2G\x80C\xe6\x8eb\x05h\xe2:Y\xaa\x08m@\
+%6\xee\xc6\xe1s\x0bB\x81h\xee\xe6w=\xb7\x8f\
+^0\xcc\x11\x83\x0d\xd3P\x8dQW\x91\x16\xac?R\
+\x89%\x96\x92\xd1\x89J\x984\xc4\xdd*?\xe8\x1a\x87\
+F6TS\xa6\xa9-G\xae?r\xe0\x16\xd8\x1a\x9c\
+\x01\xac\x1f\xc2Hk\xf5\xe5\x00oA\x88iy\xcd\x5c\
+\x16\xdc\x1c\xed\x98\x8b%(E\xc8[\x12v\xccE\x03\
+*\xff\x16\x9c\x85\x1d\x94\x8a*\xb4\xba\xb1\x8b\xec\x8d\x8d\
+ T?\x8e\xaf\xa4\x01K\xc4=X3z\xb9\x1e0\
+\x07\x8e\xaf\xf0\xde\xa1i\xda\xe3~\x97\x82\xad8\x90\xa2\
+\xe0+\xb0\xa1\xd6P\xc7Wx\xcf\x19\xfcjP\x14\x10\
+\xec\x98\xf2\xb3\xfb/n\xa3DD\xfeE\x14p8]\
+\x9b\x1b'np\x8b\xcf\x0e[\x0b\xea\x18\xaa\x84\xba\xca\
+0c\xb8\x01\x9d\xe5\x01\xebN\xb8\x99\xb2\x1b\x8f\x0aT\
+\xca\x8av\x19\xb5\xf1\xdb,\xd5\xc4*$\xf0\xee\xb9q\
+y\xa5 \xa0\xc9\x15}\x7fPY\x092h\xefC\xca\
+J\xd0\xb6\xb2z\xb3\x8aoV1\xe0C\xe1\x9dd0\
+*\x96\x04\xa3\xe1\xb0KvP\xd3\x1dSO\x9a\xf5\xb4\
+\x93\xe4\x07u\x93fQ\x892\xac\x98\xdc\xa8\x1d\xbd$\
+\xad\x12\x03zII\xaeJ\xbd$\x88<Y/\x81\x8a\
+i\xa9%\x94\xdf\x90Z\x02\x17\xb9RK`\xf2\x8e\xa9\
+%\xd0n\x01\xb5\xa4\x88f\x83jIRm\x0a\xb5$\
+\xb9<I-\xb1V\xec{<\xd3dG\xe7\x01\xdf\x94\
+\xcd\x9b\xb2\x09+\x1b\xc5\x05\x16l\x9fA\xd9\x04\xc3V\
+N\xc1?\xe3\xd5;\xf1\xf2S,\x13L\x00Ye]\
+ZMi\xa2\xb9\x1cr\xab\xe0xk\xad\xc5 \xa4\xa5\
+\xa5\xc7\xce\x9cHQ\xf7\x1a\x97\x09\xee\xc1\xaa\x87Bw\
+a\x1fp|*\xc4\xa6\xb5\x8f\xef\xcd\x80\xb0\xc2\xbf\x05\
+\xaf\x8f\xa3_U\x00\xbc\xb1\xcb\x05\x19\xa9\x9d\xf3\x0c\xce\
+\x9b\xb5\x1eB\xdc\xedQ\xf9\xea\x95\xab.\x0dj.\x8e\
+70\xca\x9d\x08\xc1\x98T\x0d\xa8z(\x1cup\xf0\
+\xac\x15n.\x01\xde\x0fw\xcd\x85\xa2\xf4;8H1\
+\xbc-T|\x01t\x9b\x11\xa0g@B\x1aX\xd5\xa3\
+p\xd7]\x1f\x1a9D^\xb6\xba\x05\xb4\xf0\x1d$\xac\
+\xc4\xec\xb0oE-t5\xe2\xb0o\xc5F\xe6R\xde\
+\xd4\xda\x9bZ\x0b\xab5\xcc\xe12b[\xdf\x07rN\
+'\xca\xaa&\x81\x00Q\x18\xd1\xa5:\xaa\xf2\x07\xe0\xbd\
+\x09\xa6\x1aP\xf9\xb7\xd0E\xae\x83\xcb\x1eP\x97\xb0\xab\
+\x1a\xbb\xc8\xde\xd8\x08\x92\xaa\xf4\xa5\xa0\x17t\xf3`\xcd\
+\xe8\xe5z\x84,b<*-5M{\xdc\xefR\xa8\
+#V\x88\xbfSH\xb0C\xa6\x8b\xdc\x81*\x14\x12\x83\
+\x11!`-\x01\xc5\x9fB\x19!\xaeRN\x19\x01\x12\
+\xa7\xae\xb1p\xdb<lY)#@W\xb6L\x1cT\
+\xdb\x81\x9e\x86H\x1c\xa4\x01\xd6\x9d\x0a}\x84\xdd\x8c\x88\
+\x0aTk&\xe5\xd8Q\xbb\xc3Am$O{yg\
+\x07_\xde\x05\x93PZ\xbc\xc5uo:i\x84N\xe2\
+L\x18\xabZE\xe6/\xd5I_\x91\xa3\x077\x0c\xe4\
+\xd9\xb4^\x91\xbf1\xed\x1b\xd3\x86\xd4c\xff\x1e\xf2\xc9\
+Y/&\x82)zn\x87S\xf4\xda\xcb\xd1\x13\x0b\x82\
+Sz\xb1\xb6\xccg\x1b!\x09\xd5\x0d\xa8\xfc[\x98X\
+\xd7\x81G%\x1a\xab\x1b\xbb\xc8\xde\xd8\x08\xaa=d\x97\
+\x8c\xa6\x1e\xac\x19\xbdX\x0f\x87\xf0\xc5\xd9=C\xb9\xd6\
+M{\xdc\xefR\x98XR\xe4.\x9c\x89\xd5\xda\x15\xb6\
+\xe2\xf0\xe5f\xa4\x95\xda\xc8\x0aP\xfc)L,\xe2\xd2\
+\x221/\xf15\x02\xc7\xab*\x95\xbf_\x22\x8b\xda\xdd\
+\xd7\xeeB\xb7k\x13\xf5f\xe0\xaf\x92\xc2\x07\xd6}\x0a\
+\x03\x0b\xbd\xa4U\x91C\xc5o\x06,\x87\x8eZ\x1dF\
+e\xe7%\x97\xcc\xa8\xaah\xb7\xfe\x08\x1c\xc9\x94\xb4\x1c\
+\x0e\x22\x11\xca\x0a\xad\xcd\xb1w\xe9My\x5c>\xcfP\
+\xc7\x81\xe6\x9am\xb7\xdbf\x09\xcd{Z\xdd\xbc\xbcu\
+|$q\xdd\xd2\xc2\xb9P\x86R\x05\x8bp\x8c\xc4A\
+\xf1I|w\x817\x93\xf1\x8b\x94\xc1\xe9\xd0x1Y\
+BDH\xf1\xd5\xa5\xa4R\x15@+1N\xa5\xa8\xaf\
+\x8cf\x10Xb\xc8\xc3\xb8\x9d\xa8DP-\x84F\xff\
+M\x80<\xc0,\x16B1x\x8c\x98\x04v\xc0\xea\x0d\
+\x80 sB\x9c\x86\xdf.\x0aS\xe1\xfb\x7f\x98\x07\x5c\
+Bf\xe0\x1c\x89A*\xd3\xc40\xae\x15G\x98b\xc4\
+h\x80a%\x19\x84\x7f\x1cdY\xc33\x9c8,\x97\
+\x09\xbcH\x8dN\x9d\x02\xd7S\xe2\xeb}\xd0O\x04\x1c\
+8\x15\xdc\xab\xf7\x0a}\xd8\xdd\xc1;\xe0\xa3\x22-\xaf\
+n|\xbd\xcef\xbb|\x13\xcf\x1e7\x9f\xd3\xdd\xe3&\
+\xc3j\x96\xfa,\x8f\x96C\x94\x89\x00\xe9\x8a\x1c\xac\xb5\
+\x04\xc3eW\xa0\xa35a\x9d\x82\x07\x8dE\xdb\x94\x03\
+J}\xff\xd4+\xe2\xf1\xaax\x8e\x95\xf1\xc8@\x1dO\
+\xa8\x90\xa7\xc6\x8f\xea\x81\xab\xc6\x0e\xae7p\xd9R\x0f\
+\xdb^\xc2\x81z\x86N\xcd\xd2P\xb5S\xab\x92\xa1\x7f\
+\x11\xb7U\xc9\xd0\xbf\xbd\xdb(\x5cJ\xba|\xe1\x05\xe5\
+L\x00[\xd2\x81\x17\x1e\x9c\x8e+\x08\x1b*p\x08\x0a\
+x\xbf<\xed%\xabc\xe3R\x06\x0d5\x18\x19K\xc1\
+\xb1\xf4\x1f:\xba\xc0\x91\xff\x059<X\x7f\x8b_\xf8\
+ \xc1\x0c\x1b\x8b)xP\xffL\xd5\xd7\xd1J\xdd\xdf\
+\xaa\xe7\xe5\xb6\xfe\xaa\xd6\x1e#@$JE\xf3\xc5\x89\
+\xad\xca5<\x1c\x5c\x91\x17\xef\xed\xcb\xbb\x1c\xde7\x14\
+U\xf5dE\xa5\x99\xf5\xbe9\xbc,A\xe3xC\x07\
+\x1c\xc4\xce\xf7\x8c\xc2D\x9c\x8a^AP\xb34C\xdd\
+/'\xd5O\xc1\xac\xdf-\x88\xfb\x12\x82\x01\xdel\xbe\
+\xa4\xc2\xdb\x8dGJ\xfc\x1fr\x00\x19\xe9\xc4\xbb5\xd4\
+\xa7\x8cbF\x02qN\x9f\xbe\xb7M\xeb\x15\xef\xb4\xea\
+\xf2\xacG\x94\xfa\xff\x9aR\x14\xcez-{,\xbf\xeb\
+P\xfd\xd9\xbf\x80\x13\xdc\xefs\xf0\x8a\x0e\x0c\xa5\xf1k\
+e\x8c\x7f3\xf7\xf0\xd4\x07W\xeb\xedm\xe0\x08K\x1a\
+\xb2\x8a\x84\xf4d\x1a\x1e8\xb5!f\xafk\x14{\xcb\
+\xd1\xc6\x9d(?\xc0\xecAr\x1dbw\x8d\xb6\x16\xa8\
+\xc8Nb\xf7\x01\x83q\x88\xdd\xf9Bff\xde\xa6\x15\
+l\xc5\x82\xc2U\xaa\xfc\x16,\xf89.\x00cg\x0c\
+\xb85Xe2\xda\x1a\x94[\xed\xb1|\x9f0\x15-\
+\x9d\xda\xa3\xbe\xea\x08\x10\xfe\xe5\x1c\x7fN\x8de9?\
+\xf9\x08\x83\x04\xe5r\x90\xa0\xc7TX\x15!LP\x1e\
+\x8a\xe8`@\x97\x9d\xb40{\xdaICH\xd6\xa5\x9f\
+\x93\x0d\x0d\xff\x8c \xb9Sn\x1d+\xf3\xdc\x9c\xd9\xa1\
+\x83\xee\x9eih\x98\x16{\xf5\xe4\xb4\xbf\xc8fK\x82\
+\x9e\x87\x96\x82\x8f\xa2\xe5\xb1s=\x85\x19\xe2\xf3r\x83\
+\xd0'r\x83w_\xec(7t\x0e\xe6\x00+\xc4\x95\
+Kg\x0er\x83\x872\x86!\x0e\x0a\xfe O\xd8\xf3\
+PT\xd2\xaf\xe1\x89\xb8\xc3\x14\xce\x04^\xe3\xb5\xb3\x8f\
+\xef\xfe\x1f2\x91g\xd1\x9do\x00\x00\
+\x00\x00\x10\xb4\
+\x1f\
+\x8b\x08\x08\xd3\x9cBb\x00\x03Gnome-f\
+s-directory.svg\x00\
+\xd5Z\xedn\x1bG\x96\xfd\xef\xa7h\xd0X$A\xc8\
+f}\x7fp$\x0f\x12\x09\xde\x0d`\xef\x06\x1b\x07\xb3\
+\x98?\x03\x9al\xda\x84)R\xa0([\xca\xab\xed\x8f\
+}\xa4}\x85=\xe7\x16I\x91R\xb7V\x1e\xc7\xd9Y\
+F1\xbb\xba\xabnU\x9d\xba\x1f\xe7\xde\xe6\xc9\x9fo\
+.\x16\xd5\xc7f}5_-O{\xbaV\xbd\xaaY\
+NV\xd3\xf9\xf2\xddi\xef\xd77/\x07\xa9W]m\
+\xc6\xcb\xe9x\xb1Z6\xa7\xbd\xe5\xaa\xf7\xe7\x17\xcfN\
+\xae>\xbe\xab0ry5\xba\x19_\xbe~}\xda{\
+\xbf\xd9\x5c\x8e\x86\xc3\xe5U=\x9e\xae\xde6\xf5du\
+1\xc4\xa3!$\x0e/.\x86\xbd\xbb\xde\x8f\xf7\xddu\
+\xbc\x9c\xce\xda;\xe2\x01:\xda;\x89\xa7=y8\xc2\
+\xf5E\xb3\x19\xef\x1fL'{\x01\x97\xd7\xebE\xbdZ\
+\xbf\x1bN'\xc3f\xd1\x5c4\xcb\xcd\x15\x84\xe8}\xdf\
+\xc9]\xdf\xc9\xba\x19o\xe6\x1f\x1b\xccu\xb1\xc2\xcc\x1c\
+\xb6\xbcz\xbe\xeb\xb9>X\xd7\xa7O\x9f\xeaOVz\
+\xe8\x9c\xf3P\x99\xa11\x03\xf4\x18\x5c\xdd.7\xe3\x9b\
+\xc1\xc18\x00\xd66\xce(\xa5\x86x\xb6\xed\xf6\x84.\
+\xa3\x9b\xc5|\xf9\xa1s\x0d\xf2\xb4W}\x9aO7\xef\
+O{.]nz\xd5\xfbf\xfe\xee\xfdf\xd7\xfa8\
+o>\xfd\xb8\x02l\xaaR\x95K\xf8\xe3\x09\xdf.p\
+\xb8+(\xc2l\xb1\xfa4\xfa8\xbf\x9a\xbf]4\x7f\
+j\x96c|\x0d\xde\x8e'\x1f\xde\xadW\xd7\xcb\xe9h\
+\xd9|\xaa\x0e\x06\xce\xa7\xa7=\xac\xcd\xf3\xfa@\x8bt\
+\xef\xc5\x09\x17\xb2\xdbU\xaf\xda\xdc^b\x82Ms\xb3\
+\x19N\xae\xaez\xd5\xbaY`$\xa7\xbdz\xdf4\x9b\
+\x22i:^\x7f\x18\x5c\xac\xa6\xcd`r}\xb5Y]\
+\x0cd3\xc3/\x94\xf5\xaeY6\xeb\xf1b/Lz\
+\xdeI[\x8c\xa9\xea\xcd\xf2\xa1\xdc\xd6%\xc9\xe8/\x10\
+\xb3\x14\xed\xda\x8byVU'\xd3fvUz\xe1\x22\
+\x04\xd7\xe3]\xdc_\x8f\xa7\xf3\xf1\xe2\x9f\xf9\x05\x8d\xad\
+\xdem/~]\xce7\x98\xf2\xfa\xaaY\xffr9\x9e\
+4\xff\xb6\xfc\xf5\xaa\xe9\xed\x1f\xbfY\x8f\x97W\xb3\xd5\
+\xfa\xe2\xb4w1\xde\xac\xe77\xdf\xaa\xdaF\x97\xfb\x8a\
+\xff\xe1\xd2\xf7\xb5\xabs\xf6\xb9\xaf\xfdw\xbdjv\x0b\
+\xcd\x88\xb5\xca\x1ag8\x83^\xb8\x5cg\xe5,p=\
+\xedYU\xabdC\xaf\x9a\x1c\xf6\x9a\x1c\xf6\xe2\xc2\xff\
+\xe3\xf5\xab\x9f\xce\xff\xa6\xfd\xdf\xb6K\xc7\xe2\x01\xd6e\
+Q\x0f\x5cx\xef\xf7J\xc6\xf6`\xb2Z\xac\xd6\xa3\xe7\
+\xc9\x9f\xfd\xf0\xf2e\xafZ\xcdfW\x0d4T\x15D\
+\xda\x04\x84V\x01J\xd9\xf3\x1f\xf2\x9d\x00\xbd\x13p2\
+<Fo{\x17:\xd0\x8c\xd7{Ho\x0d6\xa2\xea\
+l\x02\xc4\xdf\xa0am\x1d\x95\xd7\xbd\xeaV\x9f\xf6\x0c\
+\xb6h\x0c\xa4\xdf\xe8\x83'\xff\xcb1\x1c\xc0\x11:\xe1\
+\x08\xa6u7\xd6\xe6\xfc48\x82}\x92\x80\x038\x8e\
+w\xde\x0d\x076\xedc2[8B\x9dB\xde\xa2\xe1\
+j\xaf\xa3.h8[\x07\x1d\xcd\xe7\xa0\x11\xbb\xd1\xc8\
+_\x88FT\x1d\xca\xc1\xcf\xdf\x8d\xc6c\x06\x95}\xb4\
+0&\x93r\x7fP\xbe\xb6\xf7`Z\xd1Z\xd3\x0f\xb6\
+\xce:\xd0\xbe\x08\xea\x80\xa6\x93\xa2+\xa8j_\x07o\
+m\x81\xf5\xe0\x11[\xda\xd4^}\x16\xae\xa9\x13\xd7\x98\
+\xda\x8dN>O\xc2\xb5\xfd`\xbc|\xfe!p5\x88\
+5N\xdb\x82\xab\x89\xb57z\x87\xab7\xe8\x99\xb6\xd6\
+;p\xb5\x11\xa3y:\xae\xb9\x13\xd7\xd4\xee\x8b^\xca\
+\xe7)\xb8\xa6\xd8* \xe7\xb3\xb3\xcf\xb1\xde?.>\
+\xd8\x88\x1bA\x97\xf8\xa0Cm\xbd\x0e\x12\x1f\x10\x05\x9c\
+f\xf0\x9f\x1c\xf6\x9a\x1c\xf6\xba\x83\xd4\xa8NH\xb3\xfb\
+\xc2\xf8\x90\xdb\x03\xcc\xe7\xc6\x87\xdf\x13R\xed\xa8\xc3\x88\
+\x19\xa6/_Z\xd0\xd5\x80\xd7\xd6\x088\xa1\xaf\xc5\xf2\
+\xed\x16c\x9dj\xc5\xb8@\x88m\xaauH\x82p\x86\
+\x19\x04\xfa\xe3\xc9A\x9f\xc9A\x9f\x03|u\x17\xbeA\
+\xb5\x07\x9c\xfb\x1a\xd7\x89oPO\x0b8\xaa\xf6\xdd\x22\
+\xda\xcf\xd8\xda\x10:\xb4\xfe)!\xfcQo\x92U\xe4\
+\x19h\x1b\x5c\x7f\xffU\xee:\x040\xeb\xfa\xbe\xf6!\
+\xc4\xad;\xd1\x1a\x01\x9f\xc6Io\x92\xeb\x10L(\xce\
+\x84\x06a\xb2)\xbed\xf7\xe0\xc9\xae\xc4\x98\xces\xd1\
+_H\x04\x82\xee8\x97\x1f\xf3\xf9\xf1\xb9(\xefB\xb7\
+\x94\xf6\xa3\x09\xeeG},\xc5:\x1b\xbb\xa5t\x90<\
+}\xa6\x8e\xa5\x04\x15\xbb\xd5D\xb7{\xd7l\xcf\xeei\
+Z\xb2\x8f\x08\xf9}<\xecW\xd45\xeb\x8a)\xdf\x14\
+\xce\x85\xe3\xd9\xb2Nx\x87h}*\xba\x86\x86\x93\xd3\
+y\xba\xb2\xd9Ne3\xed\xba\xf2\xe4\xb8\x15L\x87\x9a\
+\x84\x1f\xed\x17\xb2N\xe7jg\xdd\x16\x0e\x04\x15\x13\xf7\
+p0\xcf\x08\xb1\xc0\x01\x0e\x1a]\xf8,\xdbs\x9dp\
+\xd8v\xdb{:\x1c\xb6\x1d\xcf/T\xb2\xdb\x92\x86\x84\
+`\xd3\x16\x0e\x0bJ\xb8c\xe1\xf0D)\xee\xd8\x22c\
+l\xd4\x9f\x93\x93\x98\xce\x14-\xd8/d\xe1\xc1u\xb1\
+\xf0\x10\xce\xce\xbe,'\x09\xc8\xbd\xa8\x107%_\xf3\
+\x8a\xd4V\x92\x92\xfd\x13\xc2aj\xa7\xec\xe7\x90<\xd3\
+\x99\x94\x04\xd7\xeeA\x9eL\x9e\x83kg\xdf_H\x9e\
+oKV\x16\x5c\x8e\xfb\x14M;xB\x81\x03\xd8\x04\
+\x13\xb7\x9c\xd7\xe9\xda;\x97?\x07\x8e\xce\x5c\x22t$\
+\xf0g\xfe\xa5z\x9avt$\xf0\xfa<\xba\xf3v\x82\
+\xf6\x10\x8e\x93!+$r\xc5R\xdft\xbc\x19\xcb\x04\
+\xbb\x86\xc7n\xb7\xa3o\xb0\xc1\x0f\x0dF\xbdm\xde\xcd\
+\x97\xa7\xdf\xfc\xf7\x7f\xfe\xd77\xec\xfb\xcd_\xfck\xf5\
+\xfa\xf2\xacy?\xff\x97\xdf\xd6\xcd/\xbf\xfd\xeb\x9b\xc9\
+o\x1f&y\xfa\xcd\xc9p?\xa6H\x18\xdd\x5c\x5cR\
+r%W\x9b\x0fD\xe9\xe7j\xb3Z->\xcc7\x95\
+\xad\xd5\xc0\xe4~5[\x8f/\x9aO\xab\xf5\x87J\xd7\
+\xe1\x0e\xbd\xdd\x92v7\xc8-\xa7\xb3\xd1\xbf\x9f\xbf\xbc\
+\xbb\xb3\xbdw\xde\x5cM\xd6\xf3\xcb\xcd|\xb5\xac\xd8\x1e\
+\xbf]]\x03\x89\xeb\xeb\xf9t\xa4\xa7\xde\x197\x9e\x0d\
+\xdeNfa\xe0&6\x0f\x92J\xb3\x81\x091\x1b\x03\
+\xcd\x9fNL\xefP\x22d^B\xc6\xcf\xeb\xd5\xf4z\
+\xd2\xac_<\xfb\x81\xc5\xd1\xea\xe7\xf3\x97\xd5b\xfev\
+=^\xdfV\xbeV\xeadx\xdc\xeb`\xf8\xf0\xde\x9a\
+~\xff\xf5\x0e\xff_\x88\xbc\x87\xea\xcd\xf8rt\xc6\xda\
+ps\x8e\xff_<3H-\x06\xf8\xd3\xea\x8d2#\
+\xfc\xe9\xf0=/\x00\xed\xfd\xae\x0f\xe4\xbc^M\xe7\xb3\
+\xdb\xbd\x1cG9&\xbfQi\xe4\xf3\xc8\xc5\xbf\x16\x11\
+\x87\xbd\xda\x97\xb2Z\xbf\x816\xee\xce\xf8\xa7\xc5\xe2\xfa\
+j\xb3\xe6\xedJ\x83\xf0\x1d,d\xd7\xf1\xe1J\xb6j\
+z\xb8\x16=\xd0\xe9\x8dN#\xe7F\xda|\xaf\xf4~\
+O\xc7\x9d\xffP\x95y\xb8\xf4\xd7\xafG\xe7\xab\xc95\
+k\xf9?\x9d\xbfx&\xa2&j2V\xd3\x94\x06S\
+;U\x037m\xdc \xa5\xd9\xdb\x81\x8fa\x12\xa6!\
++\xedg\xb2\x95{\x83\xff/\xb72\x9d\x8c\xc8$\xc7\
+p;\xf3\x8b\xf1\xbb\x86\xa5\xfe\xefo.\x16\xf0uw\
+O\xee\x8f\xd8\xcc7\x8b{Z\xb1]\xde\x0f\x8b\xcd\xfd\
+\xfb\xdb'\x8b9\x8b\xd5\xa3R\xa7\xbe\x19\xc0\x93\x8e\xaf\
+\x17\x1b,g\xb6ZL\x9b\xf5@\xd7\xe3y\xd9\xfeb\
+\xfe@\xf4\xb0U\xb6\xac\xf1\xc1Z\x1e\xc7p2\x19\xfd\
+\x85\xde\xf2\x00\xbbnH>\x03\x91\xdb\xcbFd\xae\x9b\
+\xab\xd5\xf5z\xd2\xb4\xbe\xfc\x99N.\xe6\xec9\xfce\
+3_,~\xa2\xf4c\xd7q\x00\xef\xb1K\x19n\xd7\
+}\xe0\xcf\x87\xf7\x1c\xfa\xc9\xf0\xd8\xe9C\xd3v!\xe4\
+~Pj\x96\x88D\x9f\x8eC\xce\xf1\xf0\x93\xcb\xf1\xe6\
+\xbd\x047^x\x16\x9eq\xfd\xbar\x11\x09\x81\xef\x93\
+\x08'[\x9d\xb1m\xd9\xf2\x99\x97\xca%6\x5c6\x95\
+\x033\xca\xd2\xd1\x9bP\xbd\xaa@\x0d\xac\xc5S_\xdb\
+\x14+\x9b\xea\x94\xa4\xd0\x03)\x93\x8au\x0a+\xe5\x0a\
+\xe3\x22[\x1as\xe0\xcb\x85\xcc\x96\x0d\x96\xad\xa0\xa5\xa5\
+s\x92D\xc7\xb3\xe1\x9cd=F\x07\xb6B\x96\x8e:\
+\x99J\xf5U50`d.\xf4-\xdf\x1b\xa0\xe5 \
+7\xa3eM\x92)\x95T\xf9Tp\xd22\xa5\xe6\xa7\
+\xf5\xc3\x96\xf1\xa6\x0f\x05M\xd6V\xfc\x8aX\xaa\xad5\
+\xa5\xb0\x0e\x8d\xa5\x1al'W\x8bj\x80\x1c+\xb1\xd0\
+\x12\xb1r\xd9W\xd2,(jm8\x12I\x16\x1a0\
+R,\x06`\xe5\xbe\xc6\x0c\xa6\xec\x83\xe9\x9aOe\x1b\
+\xc9\xe2\x895z\xd7@g\xc8cyL\x03h\xac\xae\
+\x14st\xe2\xb5e}\xc7\xc5\x88\xe9\xb1(\xaf\xfb\xd8\
+u\x8a\x06\xd3\xb3c.\xc9 \xafC`i3x\x5c\
+k'\xc5\xa0\x0c\xd2\xa0\x95\xc3d\x11\xd8\x02,c\xfa\
+,\x0e\xe9\x8ae\xce\xd8\xc7\xe1\xe1|0Hy\x8aI\
+\xba\xe2LY\xc48\x5cK\xd9\xae6F\xe6\xe6\x8e<\
+\x93M\xa7\xadLn\x00}9\xd9J\x8eR\x8eF\xc6\
+\x05-Gh\x83\x915\xcaYc\xa9l\x18[\xc6H\
+\xc3\x16\x01\xb2g\x9dd\x8cJl\xec\x94\x85\xd7N\x19\
+\xd1\x15\xcfU@\xa1(\x1b\x99\x09\x92\xb6\x02A\xf4\xa5\
+o\xd8\xe2\x81\x86\x17duY\x1f\x08|\xf5\xdb\xdd;\
+HX\x04lt\x84\x11\xdb\xd7c\xe0\xab\xfbW\x98Z\
+\xa9\x7f\xda\xbf\xdd,\x8d\xcd]2.\x97\x0bD\xa7o\
+\xcb\xe2d\x8f\x91EL\x1a\x12\xe4x\xcf\x14\x93/\x02\
+G\xef\xd7\xcd\xec\xb4\xf7|o]\xb7$\xaf\xd5\xcd\x9e\
+\xc2\xfe\xbd\xd3\x22I\xee\x8b\xda\x99\xef\xb6\xe2v\xa2[\
+\xa7\xdd/\xccn\xa7=\xb6\xfb\xa0vv\xefa\xce\xb1\
+o,\xad\xb82\x1a\x87\x0c\xe3\x0e\xb4{Qs\x9b\xad\
+T\x19E\x99C\xa4\xa6\x89U!\x0d\xa15\xe4\x80\xb3\
+Q5,WC\xb3T\xd1\x0f\xda\x18\x8fO\x0e4Q\
+\x8b#\xf5\x01\xb1\xaaOS\xe6\x10\x9d\xa0\x81b{*\
+%\x19d\xb7eM\xf6\xf4\xa9\xa8\x81\xa5^\x86r\xce\
+\x1e6z\xac\x06i\xab\x06\xb6\xa8\x81;P\x03\x95\x8a\
+\x1e\xc4\xa2\x07\xa6\xb8\x1e\xd1\x0a\x9d\xad\xd8e\xd1T\x93\
+r\xd9\x984|8P\x98\x19<\xf9\x08>\xfe\xdb\xe7\
+\xfb\xb7\x90\xdf\xb5c\x19\x05\xcb\x0b\xa2\xe7\x89\x1e\x5c\xa7\
+\x98\xc6\x1d*\xc7\xdb\xe5&\xf2^\x97\x1f\x991t\xcc\
+\xc8<}7\xa3\xd6\x813fG\x9f\x91\xbdT\x81\x91\
+\x9eqJ\xc3ma\xca\x88\x19C\xe6\xb5g\xfa\xdfj\
+\x14\xfeO\x0ff\x8f]\xb3\xfb\xdd\xec\x16gJ\x8f\x96\
+\xe1\x85'\xf4\x83F\xd9b\xff\x96\x8e\x10\xbe\x8b\xdeH\
+\x9cb\xa23\xf2\x86g8\x88\xf0/\x121B\xdc\x06\
+\x09\x06\x02\x19ME0}\x0e\xa5\x0bC\xff>\x87\x1a\
+\x8c\x82\xf3\x83\x17\xed\x07b\x87Ae\xae2\x15\xbb\x17\
+\xbfc*v\xd7\xdc5\xe7z\xc5\xd8\x95\xe1F4r\
+(\xf8\x06\x845\xa2\x02\x8c\xe8\x98\x13\x9f\xf2Xr\xad\
+\xb1\x10\x046\xc41\xc4/]\xfd\xf5\xf7\xf7\x1a\xb6h\
+1\x1c\xeb\x81\xd7\x88\xa1\xcd|\x89\xef\x03\xafq|\x04\
+\xc9\xde\x1d\x81\x92\x97Y)\x84\x7f\xdc#\xd09\x13r\
+\x12\x06a\x16>h\x80n\x8d\x80\x9e\x10w\x12\x19\x06\
+}\x11=LDh\xf4\x07g\xf0@1S\x87b\xa6\
+\x9dY\xc0\x04\xb4\xc3\xba\x93\x98\xf4\xa4Dz\xba\xae\xe4\
+\xe9^\x8c\xf1\x8c\x8c\x8e\xfbc\x14A\x80Sa\xb7\xbf\
+\xc8\xfd\x95 \x9b<\xa31Eh\x81k C+v\
+\xf7\xc5\xb0\x84\x00\xc1Y\xfa\xc8\xfdY+\xcc\x89\xf88\
+\xec\xcf%aK|\xbbH\xf3w\xdc\x9fC\xd0O\xc2\
+S^q\xba\x94\x03\xcf\x04\xee\xea\x8cM\xc6Y\xa0\x0a\
+M\x95\xf7\x8f\x89\xab\x84L\x83\xa5d\x84\x7f\x09\xda\xf7\
+py\x9e\xf3d2\x9b\xb5\xe2\x91w\xe4\x0e\xa2\xe1\x04\
+!@c\xcf2\x93Q\xf0\xf9\x9c%$\xde7I\xa6\
+\xf4r\xf0\x11\x94\xe3\x151\x8c`r\xc0\xd0\xf9\x02\xa1\
+&WpYh\x06:b\xffF\xfc\xb3\xc1\xe6aA\
+G\x0aR\x00Dg\xd2\x0b\x1c-;\x97*\xb6!5\
+)\x9c!\x08\x0c@%\xc3\x87i>\xcc\x05?07\
+\xe0\x17\x9c\x95\xf0\x04\xc8`\xa1Z\xf4\xc3$\x9ah\x06\
+izD?r\x87~\xf0E\x8b\xe8\x87\xf5\x0c\x03|\
+O\x96\x0c\xc9\x84e\xc9\x5c4\x16\xb3\x04x\x08iD\
+(K\xc6-\xc7\x86\x0d\xdc 8\x22N>\x80\x22\xc6\
+\xaf\x7f\xd2\x85u\xa2\x1f\xc4\x88\x83\xc5\xca\x10\xb5X\x8c\
+\xd4<\x1e\x1fM\xa1\xb2\x95\xce\xd4l\xe1\xae.\xb6\xba\
+wW\xdc\xfb\xf3\x99|\xda\xd1\xc9;tx~0X\
+\xb1c\x9e\xe3=\xc6m\xb6\x8c;\x09\xe3\xe6\x91\xa1k\
+\xc0\xfc\x08h\x1a\x86\xc4\x16\xf5\x03\xe7\x0a\x16\xf1\xa0\x05\
+'\x8b\xf4@\xc3\x17\xe0\xc8\xa3O2\x91\x05\xd2JK\
+\xbcT\xd4>[;\x1b\xd9J\xa2\x13\x90\x01?\xc4`\
+\xeay\x06\xc4\xd2A\x10\xae-\x14\x02\xb2\xd5VG\xef\
+\xd1m't{w\xfd8\xdb\xb6ml[\x1f\xb1m\
+\xdf\xca\xb6\x93\x90mq)\xb0\x02\x92mK\xb2\x8d)\
+\xee\xc8\xb69 \xdbF\xc8v\xea&\xdb\xae\x90mw\
+L\xb6\xedC\xb2]\x88h\xa0\x15\x16\xae\x8d\x14\xaa\x92\
+\xa4I\x88\xb3P\x02\x9dDKBv\x845\x96\xf4\xcc\
+\x8aqm\xf33{\x94\x9f\xb9\xa3\xfcL\x17;-\xe9\
+Y>L\xcf\xf2Qz\xe6w\xe9Y7\x9b1\xaa\xdd\
+,\x83R;\xc5CL(\xc9c\x14\x8e\xdf\x92=\x1e\
+\xaf\xce\x1c\xae\xae-y\xf4\xf7\x92G\x98\x94\x11,\x18\
+\xd3<\xb3<\xce\x07\x97\xb7\xa3\xbb_\xc5\xc7aP\x9d\
+\x09s\x86\x86\xf8V\xfb\xd4\xad\xc8\xe8\x1dK\x87If\
+/\xf6\x00\x05\x05\x99I\xf2\x92\xdf\xd0\x86\xa0u\x88\xc2\
+\xe4\x92\x89\xd1U3\xec\xea\x82\xa1\xa5\x85\xc9\xef.\xb0\
+O\xac\x03^\xd4I#\xe7\xd4\x92\xd3\xc2\x1fIJK\
+t\xa1\x86x\xa4%\x95df\x9c\xe9wH\xa4\x8bu\
+\xdc\x19\x87\xde\xba\xb2\x80\xb5\xc0\xb6aQx\x0e\xd5\xc5\
+J}\x9f6\x9aJ\x8d\x00\x9a\xc4J\x81~,\xb0\x1b\
+\xdd\xa1!f\x17\xc8\xa8\xb7\x9a\xf6n\x8d\x13\xb7\x10\xc5\
+\xb38\xfaQ\xfe\xa0\xb0/o\xae\x98\xf1\x1a#\xfe\xdd\
+f#\x09\x8a5\x0c\xf3\xd6\x97\xd4\x11\x81\x86G\x8bt\
+\x16\xff\x92\x1e\xc2\xf9\x821\xd7\xd9\xd0a\x04\xc5s.\
+\xe0\x0cv\xe8\xf0\xc7|\xe5t\x09:\xdcr\x12\x06\xe0\
+9Lr\x09#\x19\xc9B\x14\x93\xa9\xdan6\xc9C\
+\xa4\xaf\x96\x22\x83\x22?+\x13\x0e\xca\x8c\x03N\x99\x1e\
+\xb3\x1c\xd3\x85K\xda\xd1@@\x00?\x98%\xbd0\xa2\
++L\xe5J\x86\xa4%\xef\x22\x8da:G\xf7\xa8x\
+\xe9%\xb3\x8b\xc2\x88\xb0\x0fF\x8f\xac\xa9\xb9\x81{c\
+F\xa1\x99\xa9\x90\xd616{\xe6- \xfa\xec\x17\x94\
+(\x1e\x9c\xbd\xc4\x1cdw\xc0=\x1b)\x12\xc0\xbf\xa0\
+c\x8c\xc2\x908S\x02\xdc\xd8\xb2\xc7\x13\x83FrV\
+\x042\xc2\xd1\xc0\x8b\xddFU\x0c\x5cf\xabM>n\
+\xb4YLz\x90\xb0\x18\xdb\x05S\xde\xaa\x0f\x0c`\x1b\
+:\x02\x9d3+<\xd0\x1emS\x091\xa4\x04^\x5c\
+;\x0e\x93\xe6\x16$[\x04mB\xf2D{S\xe4{\
+8X6r\xa1R5\xa9\x0b6o\xa9\xfe\xcc\xa4i\
+\x898M\xe8\xbf\x96\xc8\x94@\xadZ\xb5I\x17m\x8a\
+$\x97\x89>\xc4\xe7c\x1d|%\x18\x97\xd0\x19\xc5\xb6\
+\x99R\x8am\xe7b\xdbZK,5\xce\x1co\xed>\
+G\xec\x8e\xfa\xc1\xaa\xbd\x0aYn%q\x01\xe2\xaf2\
+Uhg1$\x1e\xf87Gz<\xe7\xb71\x96a\
+\x95\xac\x1a\x9e\x80!\xdb\x98\x5c\xd4\x8e\x8b%\xa7\x82\xd3\
+\xa0\xcd\x97@h\xa8\x9f\x06X{:\x08Q\xd6H\x92\
+c\xb9IM\xd51)\x14\x85\xd5\xb1\x14\x8e8\x83)\
+\xf1I\xea\x02\xb6D\x1dV\x94\xc4\xd0@\xc0%\xdd\xf7\
+\xf6\xbe\xf5<\xba\xe5\xb8\xf3&q\xc7?\x22]\x01Z\
+\xe2L\xa2\xff\xa3\xc8/\x09%\xd3S0J\xab\xda\xf3\
+r\xfbP\xcd]\x87\x9a\xbb]\xfa\xe3\x88L\x9f?\xb8\
+U\xe2\xbd9E\x99a\xeb\x8e\xa4<\x93K\xe8\x8e\xe4\
+0\x11\xfa5(K\xdb\xd1r-\xf5>J\x09f\xcb\
+\xad\xb6Q\xde\x89u\x22K\x90m\xc4\x12c\x8d\x94\x1a\
+t\xa1OY<\x1e\x94(J\xadH~z\xa9AZ\
+\x19o\x09\x18l-}\xdd\xb4\x8c\xc8\xb2\xa0\x09\xad\xc2\
+\xee\xdb\x91\x8d\xf23^\xf3\x10\xe0\x8eBO\xf0\xe6\x0e\
+`\xfe\x84\x94\x9a\xab\xc4\xa9s\xaa2\xd3vWq\xbb\
++b\xe2\x85\x85\x96\x1c\x5c\x09O,+\x1cl76\
+\xd8\xee\x8c\xd5\xbdR\xd2\x84\xd1\x0ddH\xbf\x8c\x97\xb8\
+\x11\xa5\x1c\xad\xc4\x07\xd1\xe3\x84,X\xc2\xb3\xc4\xe0\x91\
+\xfd\xe3\x9ea\x5c\x93$\xba\x92\xdf\xfbjj\xb0\xda\x9d\
+\xdfW\xca\xf0\x095\xbd\xe5\x80?'y\xb2\x12\x1f\x14\
+\x97V\x8b\xdbw\xabe\x81\xb9\x5c\x07o{\xd5\xe5j\
+\xbe\xe4\xcf\x0a\x1cy\x89!{\x80\xbb\x00EL\xf0\x0e\
+V8\x1e\xdf6DV\xb6\x09\x8b\xa6#\xa1\x1a::\
+o[\xdd\xf3\x07\x08\xbb\xd3q~dJVDwS\
+\x92\x88\x82xB\xaeC\x98\xb6\xf0l6\xf4\x1d\xcf\xc0\
+\xc9\xfb\x0e\xe4\x1c\xaeT\xac\xbbcvG\x91\x22\x04}\
+\xc7v5\x18\xbcEz`K\xf0\xd3z[\xe1\xad\x06\
+\xfcU2\xcf\xa1\x10af`\xd8q\xa9\x93\x07z\xc5\
+\xe8\x8bGQN\x18X\x96\xc3@\xdcU\xb4QO\x13\
+9nt\xbb\xc7\x13\xbe\x06{\xf1?\xc6\xc8&\x02\xb0\
+5\x00\x00\
+\x00\x001:\
+\x1f\
+\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xec}ms\x1bG\x92\
+\xe6\xe7\x9d_\xc1\xd3|\x19E\x00\xc5|\x7f\xd1\x8cw\
+c\xd6\xde\x99\xd8\x08O\xec\xc6\xcd\xee\xde\xde'\x07\x04\
+\x822ohRGR~\x99_\x7f\xdd\x00\xc9j\x08\
+j4\x80\x06d\xc9g\x94)\x03\xd5\xd9Y\x95Oe\
+eeeWU\xff\xe1\x9f~\xfc\xee\xfa\xec\xfb\xc5\xdd\
+\xfd\xd5\xed\xcd\x17/\xb0\xc0\x8b\xb3\xc5\xcd\xfc\xf6\xe2\xea\
+\xe6\xcd\x17/\xfe\xf3?\xfe4\x8d\x17g\xf7\x0f\xb3\x9b\
+\x8b\xd9\xf5\xed\xcd\xe2\x8b\x177\xb7/\xfe\xe9\x1f\x7f\xf3\
+\x87\xff1\x9d\x9e\xfdyq\xb3\xb8\x9b=\xdc\xde\xbd:\
+\xfb\xe3\xc5\xed\xeb\xc5\xd9\xbf^_\xbf\xbb\x7fXf\x9d\
+!\x15(09\xfb\xeb\x7f\xfd\xf9\xec_~|{{\
+\xf7p\xf6\xef\xd7\xef\xdeL\xff\xf5\xe6\xac,3\xffk\
+U\xe6\xab3+\x00g\xff\xfc\xee\xea\xfa\xe2LQ$\
+^\x9e\x9dM\xa7M\x11\xf7\xdf\xbf\xf9\xcd\xd9\xd9YS\
+\xbf\x9b\xfbW7\xf7_\xbc\xf8\xf6\xe1\xe1\xed\xab\xf3\xf3\
+\x9b\xfb2k\x8b+\xf3\xdb\xef\xce\xff:\xfb~\xf1\xa7\
+\xdb\xbb\xff\xb5x}\x8e\x05\xce_\xd4;f\x1f\xbea\
+Y\xd3\xa6\xfc\xff\xbaZ\xfc\xb0\xb8\xfb\x97\x1f\x1f\x167\
+m5\xee\xcfy\xfd\xf6\xab-\xb7w\xe4<GX\xbf\
+\xefb\xfe|\xe3\xdbww\xd7\xe5\xf6\xee\xcd\xf9\xc5\xfc\
+|q\xbd\xf8nq\xf3p\xdf\xd4\x12\xbb\xe4\xf3J>\
+\xbf[\xcc\x1e\xae\xbe_4\xc5|\xd7T\xa8\xbd\xb3)\
+\xfb\xb7\x1d\xe2\xbb\x8b\xcbg\xea\x1f~\xf8\xa1\xfc\xc0K\
+\x22\xcc\xccs\xa0s\xa2iC1\xbd\xff\xe9\xe6a\xf6\
+\xe3t\xfd\xd6\x06\xcc\x0f\xddJ\x00p\xde\x5c\xab\x94\xbb\
+Q\xbd\xfa\xf1\xfa\xea\xe6o\xbd\x95Y^\xed\x96\xde\xe8\
+\xd3\xdb\xe6\xef\xf9\x86\xa7\x8cr\x7f\xfb\xeen\xbe\xb8l\
+\xee\x5c\x94\x9b\xc5\xc3\xf9W\xff\xf1\xd5\xf3\xc5)\x94\x8b\
+\x87\x8b\x0e\x9b\x86\xe9\xfd|\xf6v\xb1V\xeeS\xe6\x0a\
+\xaf\xd9w\x8b\xfb\xb7\xb3\xf9\xe2\xfe\xfc)\xbf\xbd\xbf\xab\
+\xe0\xb8\xcc\xb8\xba\xf8\xe2\xc5\xd7\xb3\x9f\x16w\xdf\xac~\
+\xffpu\xf1\xf0ms\x99b\xf9\xf3\xdb\xc5\xd5\x9bo\
+\x1f\xea\xef\xef\x1bm\xf9\xe7\xdb\x1f\xbfx\x01gp\x86\
+\x14gO\x17n\x1b\xce\x97\xd7\xb7?|\xf1\xe2\xfb\xab\
+\xfb\xab\xd7\xd7\xab\xe2\x167\xb3\xe6\xeb\xf4\xf5l\xfe\xb7\
+7w\xb7\xefn\x9a\xc2n\x16?\x9cun~\x92\xea\
+U[\xdbF\xa0\xb7w\x8b\xfb\xc5\xdd\xf7\xab\xdb\x9f\x00\
+x\xf5\x5cm(L\xcbKORu/\x89\xad\xdfu\
+q;oph\x98\xbe\xb9\x9d6|\xbf\xbf\xba}w\
+?};k\x10n\xda\xf0\xef\x1b\xb4\xafg\xf7\x0d\xed\
+\xf9\x7f\xde7\x1c\xcf/f\xdf_]\x9c\x7f\xb5\xb8\xff\
+\xdb\xc3\xed\xdb\xf3\xfb\xa6\xdf\xbf\xbe\xfdq\xbd\xe4\xdbw\
+\x0fo\xdf=|\xb3h\xbb\xce\xaa\x0a\x0d\xf2\xb5\x19V\
+\x97\x97E=g\xae3X,\xcd\xc1\xf4\xf2\xeaz\xb1\
+\xaa\xe7\xf9\xb7\xb7\xdf-\xce\xdf^\xdd4\xb0\xdf\xdd6\
+_\xe6\xf7\xe7\xb7?\xfe\xf4fqs\xde\xdcq\xddb\
+y>\x9b?,\xbb\xe9\x86Loo\xde|\x90\xfd\x8f\
+\x17o\x1b}3/\xfa\xc1\xcb?\xd5\xcb\xff\xf8\x87\x8b\
+\xc5\xe5\xfd\x93V\xb4\xdf\x11\xda\xdcF\x89\x17\xb3\xbb?\
+\xdf\xcd.\xae\x9a\xae\xbb\xc6d~{}\xbd\x987\x0a\
+2\xbb\xfea\xf6\xd3\xfd\xb3J\xad\xdf\xc2\x8e\xde\xf0\xb9\
+o\xa0l\x08Z\xd8\x1f~\xban\xe4m3\xa6\x0d\x8b\
+\xc6r\xfe\xf6r\xf9\xf9\xfd2\xeb\xb6\xd1\x85\xab\x87\x9f\
+^\xe1\xef_\xac\xe8o//\xef\x17M)\xd0\xfe~\
+,\xa2\xa5d\xc7|qv~\x00kx\x9f5n\xb0\
+&\x5c\xb2>_\x97\xe5\x1f\xff\xf0,\xfc\xdbFQ\xde\
+.\xe6\xad\xadZ\xd3\xa5\x87\x9f\xda\xae\xb9N\xc6\x17\xef\
+\xa9\xed\xdbo\x9a^4U8k\x0c?\xb4\xff\xe2\x06\
+\xc1O\x8d\xc0\xed\x05X^\x87\x8d\xeb\x7f\xff\xe2\x85\xc3\
+&\x83\xf5b\xa7\xb7wWo\xae\x1a\xe5\xe4%\x91T\
+\xd2\xa5\xa8\x1d\x19\x08\xa9\x11\xf8\x97+\x1f\x9a.\xe5\xfb\
+nv\xf7\xb7\xc5\xdd\x1a\xaf\xa6\xc1\xe7\x7fk\xc9\xffx\
+ww\xfb\x03\xfeeq\xb3\x12\xa7\xe1\xbd\xb8i\xb5\xfb\
+\xdd\xc3\xed2\xe3nq\xf9\xbf[S\x03O\xbf\xfe\xbb\
+\xfez\xff\xfe\xaa\x8cO\xc6\xf1\xd5\xa3m\xfc}\xd3\x19\
+\xde\xce\x1e\xbe\xad\x1a\xd7\xfebV\x7fT\xc2&\xe7/\
+g\xad\xdb\xd0\xfc\x9d}}\xa6\xcd\xb7\xa9.\xbfN\x91\
+\x8av\xb2\x97\xb9\xcf\xa4\x7f?{\xb1\xd6\x0b\x1a\xd3r\
+=\xbd{w\xdd\xf4\xf6\xef\x177\xb7\x17\x17M'\xb8\
+\xbb\xfd\xdb\xe2\xd5oa\xf9y\xfc9]Z\xfdWX\
+\xe0\xed\xc3\xefW\xf0L\x1b_\xe7\xee\xe1\xd5M\xe3\xeb\
+<\xf5\x94f\xa0\xbf\xb9oF\xa8\xef\xbex\xd1Z\xa3\
+\xc5\xef\xa0\xc8\xcb\xb3\xbb\xdb\x87\xd9\xc3\xe2w\x18\xf0r\
+Eq\xbd\xfc\x09\x13x\xb9\xea>+~;\xc1\xbe,\
+s\x04\xf0\x95C/\xf4}\xc8\xcb\xa7\x88\xfc\x16\xe0G\
+\x83\xfd\xd7\xd1`\xff\xf5P\xb0\x0d>/\xb0\xa9\x0b\xb6\
+\x1d\x80\xf5\xd7#\xed\xc9\xd7\x87\xda\x13\xfc\xcc\xecI\xf4\
+\xda\x13*z\x08\xf0\xa3\x95\xfc\xebC\x95\x5c\xe2\xf3R\
+\xf2\x18\x80\xfb\xa8~\xc1rP\x97C\x9d\x02\xa4\xa8\xf7\
+o\xf5\x09\x964B\xc5\xda\x8f\xf7:\x06\xe1\xad\xa4\xe3\
+\xfd\x5cC\xe4\x01?\xb76\xd6>~\xae!\xb6\xbe\xcb\
+\xfe\xac\x87\xfd\x5cC\xf4\x0f\xfb\xb9\xed\x97\xd9\xf5\xcep\
+,\xe7\xba\xaf\xbe\xbd[4s\xf3\xdf\xae\xf3b\x02\x7f\
+\x86l\x9d-Q\xe8\xf2\xd2\x9b\xc7\x8c\xff\xbc\xb9zh\
+&\xdf\xef\x9aY\xd8_\xdb)\xe1\xbf\xdd4\x13\xb25\
+\x8a\xff\xa8\xca\xfb\xdd\xec\xe1\xee\xea\xc7\xdfa\x01!R\
+\x99@\x9b\x0a\x92\x01\xca\x84\xb0h\xb6_\xa6A\xc5\xd0\
+\x13_.\xf9\xcc\x1b\x05\x94,\x80\x98\x8e\xab\x9cF\xe9\
+\xa8\x98\x0b\x83\xc72\xe7r\x83\xe6r\x83\xe6\xae\x9dE\
+;\x89ar\x8f\xfel\xaa\x08\x11\xd3\x90\x8a\xbc\x96\x14\
+\x9a\xed\xa9\x22D,\xc3*\xb2\x90\x8b\xf9<\xdfc=\
+\xa0!Dl\x1f\xd6\x90\xfa{\x84\x86TX\xfa\x10\x0b\
+\x1e\xad!P<\x125\x97\x1a\xf2\xfc\x83\xb0\x80\x85\xca\
+\x84\x8b\xa4\x13\xc5bJ/WU\xc5e\xfb\xa32\xac\
+\x0a\xff\xa9\xc9p-\x8c\xc0\x18+\x12\xfa\xe2EP\x91\
+\x10\x13Z\xd1P\x87fg\x8d`b}\xb1\x15\xbb\xda\
+\xa6\xb5Q\x98\xd874b\xdf\xc9\xf5\xd9y\x0f\xeb\xdc\
+P\x89='\xd7\xa7\xd3\x97\x0aZ\xbf\xbe\xe0\x11,\x0a\
+\x22\x09\xe7\x04\x0b\xb0\x0a\xdbd\xda~C3\x9e\xb4\xd7\
+L\xc1'\xa6E\x1d\x94'S\xc9\x82B(\x1d\xe5\x89\
+\x22\x19j\xf4\xac=P\x02QA\xd2\x9e\xd5G\xa28\
+\x93\x13?\xab\x0f\x156u\xb2\xdcC}\xe0D\xb1\x15\
+\x82\x1db+\xa4m\xda7\xb6B\x88?\xeb\x98\xe3y\
+\x04\x0dQL\xafcNH\x0aMPJ@B\xa3\x12\
+\xee\x05Q\xfdS\x18s\x98HO\xa4\x22\xe4\xc3*2\
+[\xb4i\x805n\xb2\xce\xd3\xab\x08i\xbf\x8a\xf8)\
+\x8c\x08\x14\x8e0\x8f\x09\x14!0\x91\x89AA\x08\x9a\
+L\x85\x0b1\xa8\xad+\x0cd\x84<+L\x14Ie\
+$\xaa\x0a\xe3\x85\x1d\x22\xe2Ya\xac\xb8\x03Z\xfa\x93\
+\xc2pIW\x10\xd0\xdd\x15\x86I?<\xea0\x9dl\
+\xd4a:\xe1\xa83,1\xf0!]\x04\x8a\x05\x8b2\
+\xd9`_a\xd0S\x85\xaa\x19N\xef\xc23p\x7f_\
+9\x86\x83\x96\x99\xd9:\xeb^B\xd0\xc4\x16S\x9eh\
+13\xf0\x5cLeB\x05$\x18\x9a|j\x07c\x12\
+\x22\x96\x96\xc8\x8b\x06\xb2z\xed8,\xc5\xdc\x8d\xf3\xb9\
+\xe3x\x11#r[\xe5\x5cn\xd0\x5cn\xd0\xdc-\xfb\
+\x96\xa6b\xb6\xe0\x1e\xd5y\x01\x8d^\xe7\xc5\xf1\x08X\
+\x86\x9a\x02\xb5\x8en\xa6\xae\xec\x8e\xa7\x19\xb5Y\xa1i\
+,\x13D-\x8a\xc4\x93)aI\x16\xcf\xea\xbc \x16\
+&\xe3\x90g\xe7E\xbdppf>\xfb.(E\x92\
+\x95qEC\x95f\x0f\xdf\x054>lg\xc0`w\
+;\x933\xb7\xcd)\xf5\x0e\x93!\x9e]\x0cO\xc5\x0b\
+$%\x01\xdb\x8b\x8d:Z\x9f-\x03\x87\x0d6\x0a\xc2\
+\xe8[m\xda\xfc\x82\xe6\xbb\x9aK\xb0\xd8(\x22Q\x1d\
+9\xf4\xc5\x80\xc8\xbb\x97A\xbb\x9b\xe4\xd7\x19=\xacO\
+j\x97@\xa3\xd7.\xd9x7O\x0b\x99\xb3`ku\
+\xb4\x80\xa2\xa1<Z P\xf7\x94\xd5t\x80\xda\x1e\x15\
+\x5c\xdc\x15'S\xb3\xa2\x1c\x1a\x1d\x8bd\xc5\x5cM\xe2\
+\xd9\x22\xa5\x16\xb7$\xaf\x16\x09\xad\x10:\xab\xd4\xa1\x5c\
+\x0a\x0aR`\xc7\x22\xb9\x98\xc0\x1e\xf1\x06\xcd\x0fw1\
+2\xd8\xa3\x8bU7\x7f\xb8\x8b\x0d\xdf\xb7\xd97^l\
+T\xae\xafo\x91\xc1\xa6\xe2\xbb\x8e\xabz\x97\xfb\x1e*\
+\x0f\x00\xf0\xf1U\x9e4\xb7\xa8\xfc1\xdcV\x95P\x9e\
+`\x11KDY\x8e\x10\xa0h1!*\x16\x9a1A\
+r*)\xed\xb4\x98\x12\x8b\x00U]G-N\x0e\xee\
+\xcf\xba\xaeQ \xd2\xc2\xab\xae\xaf\xd1\x5cn\xd0\xdc-\
+'>(\x9c\xa6{\xc4\xd6\xd4O\x14[\xd3<Ul\
+\xcd\xf0\xe4\xfaB\xea\xfd\xfar\x8c\xe8+1\x1a\xda\x04\
+\x0b%\x0aa\xa3\x14X\x1c\x96YX\xd0\xa35\x8e\x82\
+X\xc2\xa5\xb9\xc6\xa4E\xb5\xa30B\xc5\xd0\x95\xeb\xc4\
+\x18\x09\x8a\x09>\xcdj6h.\xbb4u\x9e#`\
+\x11\xfbD\xde\x12\x07\xf4\xe5\xf5u\xb3ti\xa3I\x07\
+&\xc5\xcb\xa9\xf9\xde|apF\x9c\xba\xeb\x04\xa7u\
+\xc7\xe0\xd9U\xa3\xe8\xfaq\xfa\xec\xe6Q\xec\xd8\xf6\x9b\
+\xd0a\x985\xe3\xcao\xfe\xe1\x1f\xfe\xe1Q\xceZQ\
+\x0ck\xdd\x9f\xde\x09\xce|\xfe\xc18C\x05\xb4\x91\xb2\
+\x9f3\xf5p\xfe\xe1\xdb\xab\x87\xc5\xe6\xc4\xa9\x0b\xe8#\
+\xdfO\x03@M\xf3>\x005-\x07\xc4<\x08>M\
+\xc7\x13\xc3W\xfb\xda\x7f\xff\xe5\xeb\x7f\xfd\xea\x1b\xfaf\
+7\x88*\x9e\x15\xe7.\xfe\xb5Q\xaal\xdd\xda\xf5*\
+\xdc\x9f\xfe\xf4/\x7f\x04x\xb1\x86\x03m@T\x85\xec\
+e\xf3\xe5\x97\xef\xb3\x91\x8a\xc8\x11\x03\xdd+\xdc\xf2\x9b\
+\xbe\x19\x22'\xee\x01iJa\xe1\x8a+\x02\x15\x16\xf1\
+\xfa\x08\xc3\x8a\xb2\xda3\xc0)E\xf9qf3^\x0c\
+\x84-r\xf0>rhG\x04^\xab}\x98\xae\xd5>\
+L\x8fU{\xdcR{=B\xed\xbdPr\xad\xbc\xb6\
+?\x8fUw\xdaRw\xdf\xa7\xee\xd6\xa9\xbb\xd4\xbaG\
+\x01\x00\xaa\x95\xb7\xd5\xef\xb3\xf3\xea\xbb\x1c^{\xff\xa6\
+\xcfc\x91]<\x96\xea\x8b\x02U\xa7\x02\xa90\xc8\xb3\
+\x83\x89\x9cE5\xf4HU\x8e-U\xf6#W9W\
+\x96\xe7\x0f\x8d\x1f\xd6,\xd0\xbe\xf9\xb7\xd7\xff\xa7\xa9\xe0\
+\x92f\xf1\x7f\xdf]\xdd-.\xeaz\xfe\xfd\x97\xef?\
+\x19\xd3\xa6|X[\x13\xbe\xbe\x22\xfcY\xda\xb5J\xac\
+\xc6\xb4?\x5c\xbdz\xfb\xe6\xf2\x7f..7\xb0ZV\
+\xe1\x9b\xabZ\xf27\x0d\xe1\xea\x9e\xf3\xa7\x9bZ\xc9\xce\
+\xd7\xb869\xbf9\xa5QEb\x87\xcf\xdb\xaaVA\
+\xe8s4\xab\xb5\xfa\xf2\xf9\xd9\xd5Zy;\xada\x1d\
+_\xfd\xad\xb5\x8f#\xfbjG\x8e\x9b\x13C\xf6\xd5^\
+0\xf6\xe9\xc0S\x97\x12\x04\x0e\xdei\x03(A\xecu\
+u\xc7\x14\xa3 a\xd6\x8eP\x89>\xaeh\xf9y\x8a\
+Vg:\xfd\xb3 \xe7}\x94\xce\x8bc\xba\xd4\x9e\xe3\
+%\x02k\xf7\xd9 ir\x18\x8a\x08bh_\x1c\xa3\
+\xb3\xee\xb1\x88\x83\xa0-\xa6\xed\xf2\xc7\x8f\xd8\xc6\x9a\xee\
+\x1f\xb5\x8d\xab\xcfs\xfc6^\xe7\x8b\x9aa\xcf\xde\x0d\
+YI\x95\xae\x8f\xc3X@\x14TW\x91\x9d\x0d\x9a\xcb\
+\x0d\x9a\xc6\x11\x8a\x92\x16\xa8<\xbc\xecK%=&S\
+*\xa9\xc9\xb1\x8c\xe3\xc3\x04J\x82\xba\xd3\xc4\x8b)\x90\
+\xeb\x04\xa1\x84\x07\xf8\xcb\xe1V8\xb9%\x0eS?\x81\
+%n}\xac\xf5\x92z\xcb\x97\xfc\x04g\xeda\x8a#\
+'\xee\x95\x13\xf7\xcc\xdd\xdb\xbc\xc6\xfd<\xa2\xf9\x0b\xb3\
+\xe8oi\x97}\xba=gQF\xaa^O\xed\xee\xf5\
+b} \x8b\x05\xc3\xf5\xf4\xfa\xea\x22'\xd0\xd7\x8f\xd6\
+\x08.v\xeaF8\xf9$\xd34\xe4\x18\x8b0<\x9c\
+\xf8iQ[\x066\x89&Y\xd8\xd0\x81p\x82\x05\x8d\
+\x9b$/\xf7\x9b\xaf\x9e:,`\x1a~\xb8\xf8\xd5\x01\
+\x88f\xd8\x1f\x19<\x18\xaf\xa8=2\xa6\x12\xd4\x07\xca\
+P\x00\x019\xeb8*\xc5\x15P\xea\x03\xe5u\x9a\xcb\
+\x0d\x9aF\x0c\x82\xe2\x81\xa4\x03\x8a\x81K\x85\xc0B\x89\
+\x86\xd0\xaa\xc7\x14\xb5\xa8'\xc7\x0e\x03\xe6\xc9cB\xf4\
+y6\xfep\xe4\x88\x22?\xedN}\xdaP7\xfdB\
+B\xdd\xf4Y\x87\xba\xe93\x0eu\xd3\x09C\xdd\xa7\xef\
+\xfdN'\xeb\xfdS\x8cb\x1c\x946\x99Z\x09\xb66\
+}b\x83:\x91\xeb1\xec\xfa\x14\xb3d\xfb\x89\xc94\
+\x0e\xb0\xf0\xcd\xce\xcb\x87\xc5\xddN\xfb\x01W\xa4L\x82\
+/\x9a\xfb\x16\x7f\x9e\xbd\xbb\xbf\xbf\x9a\xdd\xfc\xf3\xf5\xbb\
+\xf6\xfe!\x0e\xed\x04\xe6\xe2\xab\xe6P\x8f\xd9\xc3\xd3)\
+D\x9c\xa2(\x9d\xa5\x00\xebL\x99\x84W\x8b\x02V%\
+\x9f\xb4=\x04\xc4\x8e\xd1\x1eT\x04\xda\x0f.\xa6\xb6\xef\
+\x90{\xe4\x89\x81!r\xfff\xce\xacs\x16.\x12n\
+T7\x83\x89\x17\xc8\x08\xaf\xc3\x0b\x16SO\xcb:\xc0\
+P\x16$V\xb2\x83\x82\x0a\x838\x1a\x97\x94\xb4hA\
+|.s\x8aE@\xdc$\xaa\xfd*\xc4a\x18\xf9\x5c\
+\xf9)r\x09\x93Lz\x92\xb0\x12\x1d\xbc\xa4\x81)c\
+x\xcbE\xc4\xf6\xcdn\x9b8\xd4\xe0\x95\x97T\xc9:\
+\xa88\x171\xb2\xe8\x0c9^\xda\xdf\x18U.(,\
+\xe68\xbcf\x9a\x99\xf9\xd9NF\xfbI\x9c`\x16\x17\
+\x0f\xe3\x09c\x81\x0ce\x7fy0BD\xe0\x83\x081\
+\xf1\xe1\x08e\x09I\xb0:\xa7\x86\xce,\xb5\xa0)@\
+G\xa9a\x08\x94\x09\x17~\x84\x85\x8aj\xf2r\xa7\x0a\
+\x14\xe3\x0c\xf2\xc9\x14-\x0b1:N,\x8b)X\xe6\
+(td\x18\x1d\x94C\xd1!-\x1e\x86V\xf5\x87\xb3\
+\x90\x05V\xfd\xa94\x9d\xb5\xf0\x5cP\x9dx\x87\xe81\
+\x96\x5c~&p8\x0a\xac\xca\xc3\x91\xe4\xccOEG\
+\xaa\x86@\xd5\x8c\xaa-K\xc5\xe0@\xb4Gm\xc1D\
+\x1e\x85\x0e\x8e\xd0\x91O\xcb\xc6$\x1a\x89\xc6D\xa0X\
+\xfb\xd1\x09S\x01\x0b\x03\x1a\x83\x90\xe4)m\x0cS\x85\
+F\x0a30Q\x1dW\xb4\x04\x03!Y\xed?@\x85\
+\x11I\x86W\x1d;\x0a\x85-\xc1\xa1\xe5\x06JQe\
+\xf5\xc9\x94d\x14\x1e\xbe\x83\xc6\xc0\xc1V\xc5W\x9d\xbe\
+\xc2\x82$\x05\x12\xb5\xc2\x92\xb9\xa4\x09\xad\xdb\x83\xa98\
+\x85\xb1\x1c4,M\xa6\xba\xeau\xab^\xb5\xca\xb5Q\
+\x18\xe9\xa0\xcd\x11\xc6C1R\xc9\x02\x86,\x1d\xcb\x9b\
+\xc5]\xac3\xe1B\x93b\x96Us*\xcdv\x8c\xb2\
+8\x9aj\xe4bJ\x8f0!\x03br;\xb5a0\
+\xb4\xf4F\x9f\xb0(\xb0\xf28\x9c\x06m\xb3\x0b\xd1\xbe\
+8\x1d{d9\xd2\x88\xd7\x8b\x02\xca\x98\x11\xea\x97o\
+\x83IYF\xd8\xe0_\xf8\x18N\xca\xe3\xc7\xf0}\xf6\
+2s\xdf^f\xdd}\x03\xd4\xdc\xe7\x17\x17\xbe\xeb\xc6\
+9\xd1\x18\xb7\x97\x19\xc7\x9f\xa0\xd1\x07\x07\xcai\xce\x02\
+`\xb4\x93\xedo\xc68\x1d\x1cp*8\xe8tp\xc8\
+\xe1;\xdd]\x88>\xd8\x1f\x5cHv\xef\x0f\xaf\xa5I\
+\xb6\xff\x86\xc0\x9c\xe7|\x86{o\x08T\x96\x18f>\
+\xbfh:)\xeey\xd2\x84\x0b\xd9\xe1p\x920~\x10\
+N\x12\xe6\xe3\x1c\x950^7\x8b\x90\xa6\x83\xe7\x8b\x8d\
+:\xea\x0ee`\x9b\x86\x9b,\x92<p\xb3\x08\xef\xdb\
+k)\x9c\x1b\x5c\x02\x08\xd3c\x8b\xb9\x5c\xcc\xda\xb4\xeb\
+~N\x11\xdc\xdd\x12_\x5c6i\x03\xcd\x11\xca\xc1\x99\
+C\xd6\x05\xd2b\xb1\xafu!\x01\xdc\xe5\xe0\x95y\xb3\
+\xdbj\xcf\xee@\x02<\xde\xd8\x0e\xfb\xc8}\x06y\xc4\
+\xb3\xdc\x913\x82\x1fq\x87y\x09ui6\xe67\xc7\
+^1(\x8c\xfd8\xe50N\xc7\x9c]n\xce]7\
+\xe7\xb7}s\xe0\xee<\xf9\xc8\x181#\xf4b\x944\
+\x8c\xd1\xd8\xb8\xc4f\x9cc3\x18\xb2\x191\xa9\xe1\x94\
+=\xb6\xabF\x1crP\x5c\xee\xb1\xcf\xdf0./h\
+\xe7\x83\xe2r\x8f\xcd\xf23\x99\xc3B\xd6Y\xefs\xc2\
+\xfa\xe6\xb9\x9d,\xa4{\x9c\x09>t\xbe\xf8\xf0Y\xa4\
+\xc3'\x9c\x0f\x1f\x87z\xf4E\xc5\x99}\xea\xef \xa3\
+\xd5\x7f\xfa\xb8\xf4g\x82$\x935u\x87\x02\x14\x9a5\
+\x90\x00\x051\xa0\x1b\xe4\x89\x02\xc6\x0a\xfe\xa4\xed\x95\xe6\
+\xc0\xe7\xaa\xeet\x8c\xe7\xaaP\x14\xc0\x98d\xcb\x83U\
+w\xe9>X\xed\x9b\x8a\x9b\x15\x22\x11\xad\x8f\x01\x95\x0a\
+a\x88\xd5\x85(\xc6\x059\x14\xb5\xa2\x97V\xc4Bl\
+\x87\x87\x0a\x1c\xc5\xc3%&SX\xb1\xf1\x1c\x11\xc1\x22\
+\xb1\xe1gt\x06\x87G&\xac\x08\xb9V\x93\x87h\xc5\
+1\xc4\xab]\x84\xc2\x86\x12\xa4V\xa37\xbe\xc2#~\
+\x06@\xe4\x94\x80\x84.\xf1\xd0|\x06Dr\xa9\x1fN\
+\xd5\xc5\xb0G9\xea\x10\xeb%\xad\xa5\xd9\x0d\x0e\x9d\xc0\
+(\x04h\x18\x01\xa0C\x110-\x22\x81HU%\x9c\
+K\x068V\x04\x88\x8bk\x98\xd4\x1e\xe2Y\xd0\x89d\
+\x8c\x5c0,W\xea\xcf$\xd7p\xcb\xa6\x8fkV\x8e\
+\xd1\xe2\xf7\xac\xf0\xb9k\xac\x9c\xd5s\xd3\xac\x1e\xeb\xf2\
+\xa8\xb1\xf3\x9a=\xaf\xd9;,0E\x0eN\xca\xe5\x02\
+S(\x8a\x1e\xea\xfb`\xb0^W&\xb6\xbeU.\xf2\
+\xcdx\xc9\x91\xb0\x88\x10r\x05 \xa2D\xa0\xf3'\x06\
+\xc3\xa0\x8d33;\xf8\xf1\x8e\x17\xf2$\xae=\x81\xc8\
+\x8au|\x03\xe5\xe2!\xa8\x5cc\xd2\xc4\x85\xc9\x91V\
+>\xd3\xdb\xbb\xc5\xec\xe2/\x8b\x87oo\xdb\xda/.\
+\xdb\x92w\xc2\x0aJ\x18\x82\x18\xb7HEAC\x8e\xe6\
+k\x116\x0c\xf3Q\xfd\x87N:RZq\x05\xef\x0c\
+\x0c\x1e%9\x99+l(\x85\x5c#\xaa\xf9p)\xae\
+\xfd\x90\x8d\x90\x96\xf2\x84\xd6\xc2\xa0\x9eif\x85E\x14\
+\xeav/\xa7\x02\x04\x81\xb5\xcf\xac\xd3\xcc\xbb4C\xee\
+*\x14\x0d4\x0a\x9d`qs7oc\x00T,\xc3\
+HV\x01\x81\x12\xe1\x91\xd1d\xb3\x16\xf0@\x9bhI\
+\xc1\x84\x941\xbd\x8c|\x10B\x91\xfc\xb5\x97u\x84\xa3\
+ \x1b\xe9|\x8c\xefeZ\x98M\xa5\xd3\xcb\xb8\xb8\x90\
+q\x9c\xa6\xa7\xf1.ve|O\x0b+A\x96V{\
+\xda\x14\xad\x98\x85D=\x86p\x9dh\xbeF4\xdc\xd7\
+H\xc3\x0c\xbc\xf5\xc4\x95\x90\xc4\xa5\xfd\x1a\xe4\xc2\x22\x13\
+(\x82`\x808a\xa0\xa2\x9c\xa2\x13\x85\x02\xaa\x9a:\
+\xaa\xa3\xe1I;ZA\xd5\xd4\xe88v \x85t\xcd\
+\xabK\xb0\xe0\xce|N\x8a\x0e\xc1\xf5~Wb\xd7#\
+\x8dT8h\xbbM\xe0H\xcfS)s\xf0\x89\xd9\x85\
+\xb7i\xdf\x98v&\x1d\xe9\x81\x07n\xb2\x1e\xf1\xc4\x8c\
+\x89}Pb]\xd8\xde\xcf\x08)\xf0dGB\x93\xe0\
+\xe1\x12\x9b\xb9\x0cI\x0c\x80&\xb1\xa7\xc4fn\xc3\x12\
+#\xcero\x89\xcd<\xc6HlV%^ck\xb1\
+\xc7I\xc4\x97s\xbc\xa4\xfd\x1f\xe3i\xf8\xe2\xf5\xfe\xc7\
+\xa42\x06W\xe6\xef\xc3\x01{\x1cd:\xa7\x99n4\
+\xe6\x188e\x97\xe3\xd4/.\xe6{+\x90\xec\xd4e\
+.._\xef\xaf@\xe2c$f\x1c\x92\xd8\x81\x1d`\
+o\x89\x99\x87%~}\xa9\x0b\x80\xbd%f\x1d!\xb1\
+\x88\x9dd\xe9\x84\x89\xc4\x89\xcc\xa2\x89\xc2\x18\x89a\xd8\
+,\x06.x\xb1\xb7\xc4`\xc3\x12s\xf8\xc5\xc6\x03\x94\
+a\x89!N}\xc0\xac\x99Y\xdf\x9ee;\xca#8\
+NSR\x9eX\xc9`\x14\xc5\xf6\xdc\xff\xa9\x17\x0f\x94\
+\xb4\xf6\x07\x16U\xc3\xe0\xd6\xa5\x22*A\x868\x99Z\
+\x16\xcb0\xb4\x97\x1f\xf0\xe4\xdf\xce.\xbaG\xd0:\x00\
+kg\x03\x12p\xd1\x80\x1a\xdaY'\xb9|\x9f\xe4n\
+I\xa1\x9a\x12#v\x94\xf6;o}*\x89P\x1f^\
+\xd7\x90rD\x9d%J\xdd\x1b\xb4K8\xf5\xe8\x95\x17\
+\xeb\xad\xbcR\x9d\xaab\x81\x94\xcc\xc7\xda\xaer\x100\
+S\xaa\x1f\xae\x05#\x91\xb9\xfbT\x19\xc0Cw\x91\xab\
+\x7f.7\xbc\x83\xd0\x8b\x86CZ\xb4Z\xc7\x01&J\
+/?&R&\xc7\xd8y\x07E\x90\x12\x98&P\x0c\
+\x93U\xe2e?.{\xb7\x0dYD\xac\xb5\x8d\x03d\
+~L\x9c\x1c>u\x9c\xb8\xa4!H\x85)\x0a\xb1\xa6\
+\xf8G\x85\x89~\x85\xa9\xe3\xb8\xf5\xfat\xf5\x91\x9cj\
+\xe1V\xd6\xba\x03\xb4>\xfa\xd9\xb8\xbaZ\xea\x91\xc8(\
+\xfe\xf1-\xae\x09\xf7J$uY\xb8Q\x01\x0eG\xea\
+F\xc2\x12\xd9\xf1Q\xac\x0d\x92VP(N\x91\xa1G\
+\xd1\x9f\x09\x1f\xdd\x88\x9aK\xaf\xf0\x01\x9d\x88M\x814\
+w\xad\xd1S(\x1a`\xe2U\x07\xb3$\x0bs]\xe8\
+\x15Q\x8cY\xe2\x93\x1aF)p\x9f\xf3\x8b\xac\xb3B\
+\x89\xac$\x9b\xad\xafP\x12q7\xaa2S\x01\xcaP\
+\xf9x\x1211\x1e\xc7>\x91\x11\x1b\xe5\x04\xeb\xca\x15\
+\xcdB\xa4\x01\xde=C0\x9d\x09k\xcbW\x9a'\x14\
+\xc4\x0aQ\x84\xe6GE\x81\x8f\x84\x023Q\x8bBI\
+TH\xe9\xa0\x81\xa8\xc5\xcd<*\x1aX $\xa1z\
+\x90\x8c\x85;4\xb4\xb2\xe0\x8c\xa4G\x06\x83\x89\xbd\x17\
+\x0c\xe1z\x04\x97AIQR\xac\xa6\x0b\xb4\x04\x83\xd6\
+\x11\xa4!\xaa:<\x8c\xe3\xc7\xb3C\xe4\x01\xfb\xf4W\
+(\x02\x04V-\x95I\x017\x94\xfaP\xa3\xd2TW\
+\x1fJ\x1a\x11\xca\x91O\xa8\xa2L\xe8=\xe8\x1a\xf2\x08\
+\x0b\xce\x0a\x82@\x84N\xa0\x04\x05\x98\xf9rS\x92\x89\
+KZ\xfb5\xc2\x98\xc9'\x98XD\x8cxbTH\
+9\xc1\x86\xdc\x8fv\xaeg\x5c@\xd0]\xeb3z)\
+\xe9)\x10\xf5\x99$\x17U$\xac\xcf\xfa\x15\x8b&e\
+\xd6w1q\x11\x177Z\x02<\xbf\xbez\xfb\xef\x8f\
+\xaf\x81\x7f\xfa\xbe=\x88\xffD\xc5HY\xdf!\xbf\xfe\
+\xbe\xf7W\xef\xee\xae\x7f\xf7\xdbu\x94\x19\x99_\xfe\xbe\
+\xbdZ\xa3\x00\x8f\xef~_\xbd^\x7f\xfd=\xf0V$\
+\x15\x00B\x9e.\xb4\xed\xd9\xb4\xfc\xab\xbb\xdbw7\x17\
+\xdd\xcc\xffs{u\xb3\x9e\xfb\xddU\xb3\xf4\xed\xfa\xaa\
+\xf9\xdf\xab\xe7\xdb/f\xf7\xdf\xce\xee\xeef?=\x96\
+VsW1\x88WRP\x1f\xb3k\x0d\xbb/\xc3\x9f\
+bHq6\xd1\x09yIa\xd7\xb3/\x9b\xdc\x94\x92\
+\xaen\xcf\xb9x6%\xd0\xd2\xfc\x99O\x18K`\xa0\
+[\x93\x89T\xd2\x81l\xc2Y4\xc8\x8dZ\x06DP\
+\xd2]b\x22^42\x93\xdbL)\xa1\xa9\x13\x8dB\
+D\x86\x8fy\x06I>\xb1(\xee)\x90g_w\xb3\
+\xd3J\x10\x81`\xcb\xb6f#@\x09g\x8f6\x13\x0b\
+\xabx\x9b)\x05)\xa8\xcdD/\x0cM\xaa\x99-_\
+T*h\x19]\xdaV^\x89\x82\x18\xc8]\x16(R\
+\xc2\xd8\xb8\x16\xd6\xcd\xac\x15\xfb\xba\x9b]\xc5\xf8r\x95\
+m\xc8\xf2,1\xad\xca\x92T\xc1.4\xa8V\x14\xc8\
+d\x1dF4)dN\xf4\x0c96\x99.E\xd2\x91\
+\x9f\x1aG\xf2\x83\xed\xf8\xf7\xb3\xb5\xf6\x15.\x12\x08(\
+K\xc6\x1e\x85\xd3!\x9f\xb3\xb5\xcd\xa4\x02\x12\xe8\x13\xd1\
+\x92\xe8-[\xf3\x82\x1e\x81\x13\x85\xe2\xe1\xa4\xb6\xaa\x17\
+\x156\xe7\x9c\xa8\x16\xcd\xb0hE\xc8\x92\x94\x0d\xa9a\
+\x09f\x0eZe\xb6w-\x9b\x17\x12\x80\x96p\x11d\
+Q'\xc0N\xf6\x97\x8f\xd9(n\xcf,\xb0\xcd\xf4\x82\
+\xa0\xfaT\x94g\x9bG\x85R \xde\xabVz\x11\x12\
+\xa7G\x01\x22\xb5\xcd\xc4\x02\xae\xf1,)\x7f\x18\x95\xbf\
+w\xc2u\xad\x05`\x5cy>\xddu\xc47\xb7\x17\x8b\
+v-qcJ\xe6\xf7\xf3\xe5\xe7\xfe\xf1\xbfUd\xef\
+\xc9\x92\x9c\xdc\xccW\x034\xde\xccC\x914\x04\xb5\x09\
+\x14\x11\xc8\xa0lm\xbb\xb3\x81\xa6L\xa6O\xc6\xdf&\
+\xd3\xcc\x82\x82\xe2\x93Xzj\xa0\xb1\x8b\x99w/\xca\
+\xcc\x8e\xef\x9by\xac\xeb\xd5\x22\x0a\x08\x05\xe4\xc70\xf3\
+\xac\xd5\xcc\xef\xd8\xbe\x9b\xda\xe1k\x864\xbd0a\xe0\
+\xba\x1d\x05/j\x88\xd4\xb5\xa3\x88^<\x11\xb8kG\
+\x91\xb4\xa8\xaa\xd1{\x06\x80\xb9\xa8Q\xc8\x9a\xb1`/\
+\x22\x12V\x0d\xe9*\x13S\x8c\xd7\x0ci\xcd\xee\x1a\xd2\
+\x9a\xbdn\xdb\x98K\x0a\xbcg\x05)KDp\xae\x1b\
+R\x93\xe2\xaa\xc4\xbanH\x0d\x8a\x03Kj\x97\x85\xb6\
+\xd5\x8dL\xad\x85u3\xbb\x86\xb4f\xaf\x1bRm\xab\
+\x1bn\xda\xb5\xa4\x86\x05\x02\xdc\xb5\x0b\x8ee\x81\x08\x00\
+\x5c\x07\xd2\xad\x84\x92\x06v-ix\x81 I\xaf\x96\
+\xb46\xe4\x9a!\xad\xd9\xebv4\xa1d\x90ht\xed\
+hH1fe\xadv\xd4\xb3\xb8\x09\xba\xad\x1b,\x97\
+\x92J\xae\x1d3\xeaT\x14\x15=\xab\x19]f\x8az\
+\xb2\xac\x9bQ$*\xa8\xce\xde5\xa3\x8f\xd9\x00H]\
+3\x8a\x98\xc5\x12\xc2\xbav\x14QJx\x8a\xbcgG\
+\x11\x0a @\xac\xd9Q\xe0b\x86h\xd5\x90VT\xd6\
+\xec\xe8\xae\xbeS~~\xbe\xd3\xcfe\xe5\xf3\xa3Zy\
+\xc4\xe2d\xc1\xfa\xf3\x9a\xf9Op%;\x11\xd9\xff\xf7\
+K\xb9\x8d\xf2\x98K\xb9\xc7\x9f\xaa\x99O[K\xd3I\
+'\xc8\x5c\x00\x80&\x04%\xdc\xa8\x95t\x85\xae\x16\xec\
+\xbc\xf6w\x0a\x85P\xa2>x\x8cg\x81\x9f\x84\xe9y\
+#vP\xff\xfa\x0d\xa7\xaf\x90\xbf\xdax\xca\xdc\xf7Z\
+\xe7\x90~V\xac\x7f\xfc\x12\xbf|\x9fUaU\xee\xe7\
+g\xfd\xfc\xe0O\xa9\x10\x1b\xfc\x0cS\xfa\xf9\xc5\x16~\
+\x10_\x02l\xf0s\xf5~~\x09\xdb\xf8\xf9\x1f7\xf8\
+=\x9a\xdc\xaa4\xfb\xac\x16\x03\xea\xd9\x88\x09\xb2\xc7y\
+#\x17\x8b\xc5\xd0\x81\x00]\xd6\xb6\xc7.wZ\xc4\xe2\
+bc\xe5\xc4\x88\xf5q\x06\x87\xecK5:\xee\xf9\x08\
+]\xd62\xe2\xf8\x95\xd1p\xa4\xf6H\x9c\xbe\xbb\xc4\xc6\
+\x8b\xdcC\xe2\xcc\x9fQb\x91<@\x01Dq\x10\x8e\
+\xe1Wm\xf7\xb0\xe6qo\xf1\x86\xdf\x8f\xda\x99L\xce\
+\xb2}g\xb2I\xbb1\x99\x8a\xb5\x1f\xef\xdb\x9e\x8c\x14\
+\xcd%\x93Cw'C\xbd\xfb\xa0\xad\xc9u\x1b#\x14\
+$P\xab\x11g.\xa8\x09\xack\xcfp\x1d\xa1z>\
+\x95fp}\x0f(\xb7\x9f\xa7\x01\x950St\x82X\
+\xdc&R2I\xc8\xc6\x9c,\xca1\xbc\x97\xc7\x0f?\
+\x03P\xa2\x10\x12*\xd6G&Z\xd4\xa2\x0b\x8feI\
+b\x88X\xdbe\xc0I\xf6)\xc0\x03\xa3\xe1\xf9\x05+\
+\x8f\xc7 :lx\xb0\xf2H\xa1\xf0.<\x89m\xad\
+\x1d\xac\xbb\xd4\xa0\xbev\xba\xbd\xee\xa1$;l\x96&\
+\x98\xc0(\xd1mPt\x01\xf8e\x8a.#D\x1f\x9c\
+s\xd5m:\x89%@\xa13]U/\xa0\xa1(u\
+\x02\x96\x05T\x03\xf2y\xde\xa0\x5c\x8c\x81\x86gcE\
+1Sr\xe2\x85\x15\x938\x17\xd3\x98L\xa3\x801\x09\
+k\xfb\x0b\x0b\xb9\x13\xa2L\xa6\x04\x85H\x9c\xac\xf9\xca\
+%\xd3\x8c\xf3\xf0I\x1b\xb1\xd3p\xd7\x918\x10D.\
+\xea\x81\xa4uo\xa1\x14e$\xad\x93X\xec\x92\xcc\xdf\
+'\x99wI\x06\x80\xb4\xa2\xe0\x19\x96\x8f\xd3[EH\
+\xf4\xc9\xd4\xb8\xb4\xe0\x19N\xa6L%\x1d\x10u\x14b\
+'5\xc5i\x85\x8dA;+\x97\xa2\x18\x18v\xb6\x11\
+2\x15P\x0c\xab\xbdN\xb8x&\x90\x1dh\x8b\xbd\xa8\
+\x98\x99\xf9q\xec\xb1\xed\xb2\xb1]\x0eV*T\xeb\xe8\
+\x14Z\x81\xb0\xaaR\x8e\xc5]\x89\xean\xd5.\xc5\xbc\
+K1\x1cD0\x85@i\x90\x22\xc3TX\x9e\xad\x9e\
+\x04\x98!\x13.\x9c@\x086A/\x0c\x09\xd6\x5cV\
+/\x96L\xe3:\xa5\x0d\x1bu\x8b<\xd8\xa8\xb7pd\
+pU\xb1\xb4\xc2\xceH\xdc\x89\x92A\x11\xf2\xea\x0cU\
+\x9aA\x15CwR\x89\xc7n\x08\xee\x84\xe1\x13+\xaa\
+J)6\x99JIAs\xc0Q:6l\xfd\x15\xf1\
+\x97\xa3c\xccG\xd61\x1a\xd61;X\xc7(J\x0a\
+%\xd55Jb\x85HS\xde\x8b\xc4rx5c\x8e\
+\xc5\xc8\x04\xe4@\x1d\xc3\x12b\xe4\xca\xc7\xd21\x18\xd6\
+1\xe0_\x07\xc7\x8a\x98\xf0.\x83\xe3\xaf\x96\xbf\x17?\
+\x1ck\xf9\x7f\xf9\xbd\x92c\x97^\xf9\xab\xe5\xef\xd31\
+\xd6SX\xfecz\x05G\xf2T\xc6\xe8\x18\x8d\xf4.\
+~\xf9N>\xed\xe4\xe4\xff:\xfd\xde\xda\x17IFL\
+\xbf\x07\xfa\xe2p\xe8e|\x94g\x8c\xfe\xe0\x88\xf0\xcd\
+\xe7-:\xc6IE\x1f\x1f\x86\x1d\x1f\x14\x1e\x83\x8e\x8e\
+\x8a\xe6\x9e\x1e\x9d\xf1O\x14F\xc13\xe2I\xc9/_\
+y O\x81\xce\xcfi.8$N\x19\xe3w-N\
+\xe1\xdc\xd9V\x07Q\x1cD\xb8\xcadU *\x0e\x80\
+\xa6c\x04\xb2a\x81\x92\x0f\x15\x88\xb2h0j\xe7\xdd\
+\xc6Y \x08\xbd6\x92[1[?!\x0a\xad\xa0\x90\
+\xd1\x18\xb9v\x18\xcd\xc3\x0e\x95+l\xe9\xe8zV\xe5\
+\x83\x22\x18\xa8TMNafJ\xc4G\xb9*\xcd(\
+\xb9h\x84E\xfeT;\x15|\x9c\xa7G\xc1E\x11C\
+\xad\xbbu\x89\x04\x11\xb3\xba\xafV\xc8\x05\xb53\x89\x84\
+\xa2\x16.8|\xf2\x06QF\xda\xd3\xfb\xff\x1d\xc0\x01\
+'S\xa2\x92\x14\x99\xb6\xfc\x8a\x9e\x181bq_p\
+\xfc\xfa\x9chO\xc4\xec\x84\xa10)\x9a\xec\x150\x91\
+\x82\x99a^\xb5\x8c:$\xf3\x0d\x92y\x87d\xf8%\
+\x14f@*\x13(\xda\xa8S\xd1 \x01\xf5\x89\x14q\
+\x0a\xf5\x98 Iaso\xb0\xc3\xc8Bi\xce\xa3\xb0\
+\x93a\xec\x98\x0f\xc4\xceKZt\xb0\xe3(\x22l\xdc\
+\x85\xae*\xda\xfa\xe5y\xbd<\xd4/\x059Z@\xa0\
+\xa0\x01\x9bf\x03\x9f\x00'!O\xb8\xb0\x87\xa1\xb5!\
+1(\x98,\x18\xcb\xd7\x9d \xaa\xe68\xb5\xa3a\xbb\
+F\xf6iE.\xba\x07\xb9\xc8\xa83\xb5\x83a\xe7\xa8\
+\xc4x\xcd\x89,\x8a\xeeI]\xd5\x09\x85\xc8\xba\xd8}\
+\x9df\xde\xa5\x19\xd4!\xcaTamu\xc8\x15(1\
+&X@\xdd\x89\xad\xf9\x16L\xc0m\x97\xc3\xa5M\x83\
+\x9cL)\x8a\x90\x1b\xe0\x18\x15\xa2\x1d\xfcM\x8e_-\
+\xd7\x07\xb1\xb3],\xd7\xaf\x0f@z\xf1\x93]\x1e\x80\
+\xfc\x8a_/~\xf4\x09/\x1d\x18a\xd7\x09v\x09\xc8\
+\xff\xaa\x17}z\x811\xe2\xa1\xcfg\x88\x9f\x1e\x1b?\
+\xfb\x84\x97K\x9c\xde\xadB9\xce3\xd7\xfaF\xa9\xee\
+K\xa3\x1e\x8d\xd6\xb7\x8b\xab7\xdf6\xf4X4\x83L\
+Wp>\xee\xc9\xca\xc4\xe7-t\xcb\xdd\x9f-]\x02\
+'\x03\xae\xea\xb6\xa4\x13\xc54\x05\xdfZ\x95\x8dWT\
+\xf5\xbfd\x8a\xe4\x83/\xa8\xc2\xc2\xe2\xa6\xabh\xd1V\
+\xa1\xeb\x1b\xaaz\xa4\xb7\xc0\xf7\xa4G\xf5\x14\xeaJ\x0f\
+\x1e\xe9(\x86\xeb\xe2\x93\x88\x07u\xc5G\x22N<\x9a\
+\xf8\x16\xdc\xf3~.&L\x94\xf1\xd2+\xf3\x91\xea\xaa\
+\xac=M\x05\x06\xc0\xaa\xe3+\xcbiG\xaa,g\xf4\
+\x00+\xb9_E\xd7\x0d\xd5\x90\xf5\xc4`\xc3U\xb0h\
+\x8aE\x8c\xd2|1]\xd9P\xa3e\x1c\xc4\x0bi\xec\
+\xea\x04\xd7\xa3\x0f\x88R\xbf\xc1o\x9e\xc7\x80\xa9\x81G\
+a\xad\xd3j\xb6,JBO\x1b/I\xb9\x00F\xdd\
+\x18\x5c\xefy\x1e\x17\xc8\xb4p\xf6\xbc\xc17F\xeeN\
+\xea\xd9\x9c\x84p\xf8N\xad\xcaw\xf6\xea\xbb\xab\x8b\x7f\
+o6\x9d?\xfc\xb5\xb9\xb8gE\x879\x14\x1d\xc1c\
+P\xac?-?;\xed\xb1\x1c\x1eyB&Ss\xa9\
+\x0f\x87\xcc\xa5\x86\x0f8\x8a;s\xd4\xd0|\xd6\xa0|\
+\xbdz\xf0\x13\xa1D\xf9\xa0\xf2P\xa2\xf5\x03@\xd6\xa6\
+\xa1S\xa2{\x14\x88\x12\xa3\x9f5c\x9b\x86X\x17D\
+\x92^\xfe\xb4E\x83\xe4\xa2M\x83\xfc\xd9E\x01\x00\xfb\
+\xcb\xa0\xfe2\x14\xda4X\x86\x10Cff\x7f\x19\xb2\
+\xa5\x0co\xd3p\x19l\xb1\xbd\x8c-\xcdl\xd2\xa6\xe1\
+2$\x07\xe4\xd8\xd2\xde\xaem\x1a.\xc3@{\xf9\xf3\
+\x96\xf6\x8eY\x9b\x86\xf9;\xe2V\x19xK{\xcf\xb8\
+M\xc3e\x04\xcaV\x9d\xe2\xfe\xf6\xbe\xbf\xba\xfe~q\
+7\x5cD\x22n/\xc2\x06_\x1f>\x5c\x86\xf0v\xa8\
+b\x0bT\x97M\x1a.C\xd1%<\xa2\xb7\x0c\xd9\xd2\
+\xe4)m\x1a.\x83I\xb7\xca!\xb4Em\xe7m\x1a\
+.C\x153s\x8b\x1c\xb2\xa5\xfbi\x9b\x86\xcb\x08Q\
+\x01\xf3\xfe2\xb6\xb4\xb9R\x9b\x06\xcb0\x08\x03\x00\xea\
+/cK\x9b\x0b\xb7i\xb8\x0cA\xdb\xaa\xbb\x8a\xfde\
+p\xb6i\xb8\x8c\xa4\xd0 \xea/\x83\xb7\x94\xc1\xc3B\
+8\xa7omp\xd5\xd1c_dDfz\x7f\x19\xbe\
+\xa5\x03\xda,fC\x9d\xa3\xe7\xdd;\xe3\x0e!\x19\xf6\
+~\xeeV\xaf\xa4T1\xeb\xac]\xa4\x92ikk\x17\
+\xa3\xb8\x93R\xdf\xb2\xc1p\xfb\xb0O\x13\x1e[\xac_\
+\xb6\xe9P\x9f&b\xdba\x18\xde\xa6\xc1v\x05I\xe9\
+\xe7O\xfd\xfc_g\x9b\x06\xf9#H\xf6\xf3\x97-:\
+\xb3h\xd30\x7fa\xc2$\xee/\xc3\xb6\x94\x91M\x1a\
+\x96\x81P\xad\x9f\x7fl\xd3\xfb6\x0d\xf3\xb7\xb4m\x83\
+B\xe4\x96v6o\xd3\xb0o\x99\xb1\x85?\x1d\x81\x7f\
+n\xf5]#\xb7\xf9\x95\xd2\xa4]|\xbe\xe0\xed8m\
+ik\xc16\x0d\x97\x91\xaa\xdb\xcb\xd86\x8f\xd06\xed\
+\xe0\x04dDj\xbf-\x05\x18m\xaf\xd5!M\x89\xfb\
+\xcb\xa0-e,\xda4\x5cFJ\xf4\xf3\xdf\xd6\xde\x97\
+m\xdaap\xd6\xed\x0e\x00lio\x876\x0d\x97\x91\
+\xbc\xdd\x07\x87\xd8R\xc6\xeb6\xed0>kl\x1d\x9f\
+\x11\xb6\x94q\xd9\xa6\xe12\x06lH\x22\x8d\xd4)<\
+U\xec\xc1#\x0b\x12\x81o\x89@\x98{\x09w\xc0c\
+\xc6!\xc2\xa8g\xcc6\x19=\x99\x07\xd82h\x98\x8d\
+6\xb8\xc8\x12\xfd\xfcc\xcb\xc0Mm\xdaa\xe2\xc8\xfd\
+\xc6\xdca\xcb\xa07\x1b\x9e\xf9\x1a\xe5\xd6\x1e\x11N[\
+\x0a\xc06\x0d{\xacJ\xb1uD\xf2-\x8d\x9c\x17m\
+\xfa\x84=V+@,u\xe9\x9dbA`\xa5\xf7<\
+V\xe6\xe8\xf5XUz\xb4_m\x8b[\xf9\xbaM\x07\
+{\xac\xbaE1)\xda\xb4\xcb\xe8\xc9\xdbF\x850\x18\
+\xd1\xae\xa3O\xb2K9\xe4\x5c\xb7\xb4\xdd\x03\xe7\xec3\
+\xa1\xf9\xee\xa7\x9c\xc5\xee\xb1\xf3\xd7\x97\x97\xba\x11\x93\x1f\
+q\xc8\x19K\x1c\x80\x06+\xec\x8e\xc6\xbc\xa93~\xa0\
+\xca=\x9ci\x9f3\xce\xe4\xe2\xa8`\x18\x1e\x02\x86\xf1\
+\xee`,..\xebK<\x07U\x83M{\xd0\x18f\
+=\xfe\x00<\x0e;\x04\x8e\x88S\x9d\x80\xc8\x09?\xe7\
+y\x80\x00\x07\xc0!@{h\xc7\xffk\xef\xda\x9a\x9c\
+8\xb2\xf4\xf3\xfaWt\xf0F\xacH\xce\xfd\x82YG\
+@\xdbLL\x84\xbd;\xb1~\xd8G\xa2\x01\xc10\x03\
+\xb4\xa3il\xe3_\xbfu\xaa$\x95J\xa8\xbaQ\xd3\
+=`\x8f%\xe3V~Yu\xf2\x9c\x93\xe7\x96\xa9K\
+\xea\xf3\xe7\x07\xfc\x1e \xc8\x8c:fI_\xa7:\xc8\
+\xae\xa2\x0e:\xc0:\xca\xbf\x0fP\x07\xc3a\xa1\xe3z\
+\xd5\xc1q\x15u\x08\x1c\xa2\x0e\xc2\x03\xd4!\x07ER\
+\xc2\xebUG\xf2U\xd4\x91zS\xb1C\xd2\xffE\xb1\
+c^\xe6\x19])\xf0\xe5\xe7\x92\xebs\xdc]\xef_\
+r\xfe.+|\xc4\xa9\xd2\xc2)\xfc\xf4b\xca\xf8!\
+e\xff\x04\xdbP\xbcJ\x9aU\xe4\x83\x5c\xe5\x04\x9e}\
+\xacm(\xce\xa4\xd9y\xd2\xd7\xe8*fy\x05u\x98\
+\xe3M\xb9\x8a9\x7f\xa9\xaeb\x91\x97\x9e\xce\x0d\xcf\x9f\
+\x07\x1c\xe8*\x96X,\x1fN\x19.s\x15K\xfe\x04\
+\xdbp\xbcJ\xcd\xe1H7e\x1b\x8e\xf2\x19K0g\
+\xbe\x8a:Xo\xaa\x04s\xf6\xc3J\xb0k\xfeIf\
+\x06\xcc\xdf\xe5O2_\xfd\xbc\x8f\xf1\x84\x04\x7f<{\
+\xac\x82_\xcbI\xaew0[\xd6\xa3~\xdc\xe4\xf6\xf8\
+\xa5I\xd8:P\x1d\xa91\x88o\xf6}8\x9bj\xe8\
+5\x89\x18\x17\x88\xe8\xb7\xae\xe3\xc0\x87pbY\xffB\
+A``P}\xab\xa7\x19\x07\xd5\x17a\xad\x05[=\
+\x0f\x93\x7fz\xa2\xe8\xd5\x15\x90\x8fgS\x81\xe7\x01\xe7\
+M\xa64\x96q\xbb\xbad\xe8\x80\xadcq\xc3\x9a\xb2\
+\x8e\x87\xe2\xa6tm\xb3k\x12\x03a^\x8e\xc0C\xe4\
+\xd0-\x11x\xc2}\x98N\xb8\xaf\xf65q\x8f\x17p\
+\xcf\xd7\xc0\xbd7J\x1e\x99\xd7j^\x17\xeft\x01\xef\
+z\x08\xef\xb6\xc5\xbb\x8c\xbcG\x03\x00\x1a\x99\xb7\xbe}\
+\xddg\xc8:\xfa\x9c\x18N\xbca\x92\xbd!b\x1an\
+xUn\xcc$\x80\x1b\x8e\x11\xb0\x83Ds\xc5\xf3x\
+\xcdGL\xe5\x90\xad\x9e-\x9f\xbf\xfd\xe6\xfex\xd6\xdb\
+\xc9\xeb\xe5\xb3\x9f_.\x7f\x99\x88\xf8\xcb\xcb7\xcfN\
+\x7f\xb9\xb3\xfe\x88\xbe\x85\xdf\xda\xd7\xbf\xfe`>\x10\xed\
+d\xb2\x93\x17\xcb\xee`\xa9\xee\x9a\xff\xba\xb5\xa7k\x95\
+A\xfbwr\x06\xbe\xdf\xbd\xec\x8e\x9c;}\xb5\xec\xe2\
+\xdc\xd3eQ\x5cw\x9cuC\xec\xc1O\x9f\xfc\xa3\x9b\
+\x82}=ON\xcf\x9e-\xcf6#\xe0\x04\xee\xb3y\
+7C\xd6?\xfa\x8e\xe2g\x0d\x0fE\xcff\xb2\x9e\x9c\
+\xbc]N\x99\xff\xed\xf4\xb4\x0b\xc1\xd4T\x89\x90u\xda\
+9|~\xbb)\x09\xa4L\xbb*\xdc\x1a5\xf5\x88\xa0\
+\xbd\xaa\xac\xd8l\xb0\xb7\xeb}\x91\xf5\x1d\x82\xef\xce\xce\
+\xbay\xbe\xf3\xea\xe4\xfd\xb2\xe3\xfc\xfb\xfa\xf3x\x95\xc0\
+\xff~\xfaK\xa9\xad\xb2\xe1\xbb\xe5\x08\x95\x8a\xdf\x8e\xe0\
+H\xab\xef\xb9\xf3\xe4\xc9\xe9\xaf\xab\xde\xad\x12\xa6\x08\x8d\
+u\xd3_\xba\xd6\xa3\xb3\xd3\xd7\x7f;[\x82\xd8\x8f\xcb\
+\xf3\xf3\x97o^\x94\x03\xd4c\xa8\x17~}_\xb7\xac\
+\xa0\xa1\x90\xa9\x1a\xe3\xa7_'\xd0\xfbm\xe8m7W\
+\x1d\x9d\xd2^33\xdf\xedx\xffA\xc7z\xbe\x00\x00\
+j\xbezp\xf9\xfa\xa7\xbd\xf8\x96\xb1\xd1x\xe9\x16*\
+#\xba\x1a\xb1\x1bp\x8d\xbd9y\xf2j9\xea\xb2\x1e\
+?\xbf|\xfb\xb2\x03\x07lp\xaa\x0f\xdd\xe9\x9b\xaf\xee\
+\xbf^\x9e\x9f<;9?Y\x9b\xd3\xba\xdd\xed\x18|\
+\xf5\x1f\xf7\xdf\xbc\xbd\xf7\xf6\xf9/\xdd\xab\xe1\xe5\xab\x97\
+O\x97o\xab56{\x17_\x17\xbc\xa5\xc4\xe9\xd7f\
+(\xc6/\xc7\x8c\xcd\xfe\xce\xbf~\xdb\x01\x8c\xe6\xc2\xc4\
+R,\xd60w7\xe3LF\xfd\xf1\xf4\xdd\xd9\xd3\xe5\
+\xc3:)\xee\xed\x15\x86,\xd7\xea\x1c\xf1\xf5\xf7\xcb\xe7\
+\xe7\xff\xd3O\xee\xa8\x98\xd50\xa7?\x9dw\xa7\xce\xfd\
+\xd6\x7f\xe5ce4\xa3\xa8\xe7'g/\x96\xe7k\xb8\
+\xe8M\x91\x92e`\xa3\xfb\x06\xc8\xf2QW\x03\x9dt\
+\xac\xfc\xed\xbf\xffB24J\x9b+Z[h\xddP\
+\xd5`7\xa3\x9d\xa3\x94\xffmfp\xf8&IM\xea\
+\xf3\x93W+\x0f\xef\xee8_\x1e\xaf\xcc\xe7Q\xff\xe8\
+\xf17\xa7?lz\xc6\xeb\xcby\xea,\xbd\x93\xa7#\
+\x95\x9e\x8b\xd2\xf2\x94\x8f\x82\x0b\x1c\x05\xbd\x82\xfchi\
+\xceJ\x8a\x7fDE\x14<o%\xd57x\xca\xfd\xb3\
+g\xcf\xef\xfd\xef\xb7\x8f\xbaCO\x9f\xde\xfb\xbf\xd3\xb3\
+\x7f\x0e\xeeX\xe8\xc9\x93\xd3w\x9d2\xba\xc8\xf5\xec\xe9\
+\xbd\xe7\xc3x/_w\x91\xfd\xee\xdb\x9f_\xfc\xe7\xaf\
+\xaf_\xdd\xbf;v\xd45\x15\xac\xea\xf65\x81\xb3\xe5\
+\xdbr\x83\xce\xa9\xff~~\xfe\xd3\xbd\xbbw\x7f\xea\x0e\
+kl\xa7g/\xba\xfb\xba\xff^\xbf\xac\x1b\xee\xfex\
+\xde\x1d\xd4\xf8\xd7\xa2;\xb8\xfd\x8a\x8f\xee\xd5\x86\xb5\xbb\
+k/\xff\xe6\xab\xafv\x16\x11\xd3c\xd5\xfc\xf1AE\
+\xf9\xe5\xe9\xbd\x14?\xacs\xa7\xab\xe5\xd9]I\xf6o\
+7\xa9\xae\xba\xb0*\xe6\xbdD\x1a\xa0\xe2\x1c%\x0c\xe3\
+\xc8)\xa5\x98\xa7\xa4\x1as\x94T\xe3\xf8AL(\x11\
+\xccSJ\x939J\x91\x0f\x1e\x1d\xf3\x94\x12\xcdRB\
+V\x9f\xa3\xf4\x90\x8f\x8f\xbf\xdd\xe1I\xe6)9\xcfR\
+\xfaV\xbe\xa3\xefrJi^\xe3\x04\x99s\x94\xbe;\
+~D\x8ftJ)\xe6)\x09\xeb\x1c\xa5G\x9d\x9a\x1e\
+M\xad\x80a\x9e\x92\x13\xcdR\xea\x1fSJ\x83\xc6w\
+\xdf\xeb\xbf\xcc1\xe20\xc7\xc8\xeb\xf6\x0ceU\xf5\xa9\
+$>\xe8d\xff\x9c#\x9b\xa1\xe8\xbc-\xc6\x838\x9e\
+\xd0\x13\x5c\xd3\x9b\x99{J\xb3\x88\xf9\xf9\xaf\xe7\x94\xa2\
+\xcf\xcf\x1a\x1b\xcf\xcf\x7f=\xa7\x94\xf2\xba\xe6_q\x96\
+\x922\x1e\xc2\x93\xf2,\xa5\x10\x99\xf7\x93\x87\x1f\xe8I\
+u\x86\x12\xce\x12\xc1\xcemyJ\xc4\xe7\x0c{f+\
+t\xdc\x0f\xb9\xf9M\x8f\xbdj:`\xd6\x8c\x0e\xd5P\
+\xb9\x8b\xf2\x94\x88\xac44\xd1\xc7\xa5\x1aBx|c\
+\xfb)\x9f\xae\x98\xbc\x06\xc58^M1\xf8\xf8\x86\xb6\
+j>Y-n\x87\xaa\x85\x93\x1frL\x89\xc4\xd5\xd4\
+B\x8fol\x17\xe80\xc5D\xc4\x83\x98\xa6\xe4\x98\x0f\
+Z\x00N\xb3\x94\x8e\xe3\xbb\xc8)%\x9d\xa7d>\x1b\
+H\x1f<|p\xfc`\x87\x92_P\x04\x89\xcfQ:\
+\xd6c;\x96)\xa5\x0b\xd2\x04\xa2\xce\x16A\x0f\xbb\xe7\
+4\xb8\xe7|\x9a`@\x9a\x0f\xee\xf5\x9cR\x9a\xd7\xb8\
+\xe0\x05\xa9\xcb\xbb\xa7M)\xcdk\x5c\xcds\x96\xd2\xb7\
+\xf5\x9cR\x9a\xd38\x1e\xe0c\x993\xeeq\xff\xc5\xfa\
+\xb2\x17lR\xbf\x1aP?M0n\xd8T\x8b}\xf3\
+\x8d\xe0\x0e\xf9\xe1\x88\xb9E\x00\x18/\xd0\x1axB\xe0\
+\xd1\xf7\xdb(f\x03\x8b\xf0\x0e\x0dn\x9a\xb6\x86\xd2\xbb\
+c\xf1C\x1a\xd2\x16T\x80\xb1v@\xb4P/@\x1b\
+`\xdf\x96\xa0,2\x88\xde\x92e\x11\xd6\x1c\x1dX:\
+:\xd5\xcf\x90\x85\xb1Pa\x85(-B[0O\x01\
+\x86\x02\x8aR\xdde\x884\xc3\xfc\x88\xee\x1c\xc0\xbfy\
+\xd3\xaeEj$\x08\xf5\xa7\xee\xaf\x7f<`\xf7\x08\xfe\
+ai<\x9c\xd8?\xbcfw\xba\xbd\xde\xea\xda\xf7\x83\
+\xd1\x82f\xe6\xeb\xf3\x1eX\x1d\x85\x17w([j0\
+s\x7f\x9e<\x13*\xcb\x9a\xcc\xb8kt\xfalY\x0b\
+\xcc.v=]=j\xc2\xfb\xc9\xbc\xfc\xd2kbj\
+N_\x0c\x16\x92,\x87\xea\x8b\x04oO\xec\xaeF\x02\
+`\x5c 7\x05a\xb6\x9a\xba\x11%l&l\xd4\xa1\
+edN\x03\xe4\x1a6\xd8\x9d\xc36\x14\xda\x08\x87\xdb\
+\xc4d\x00:\xbc\x07 2\x8a:\x124.\xc3\xf36\
+P)\xc0!\x0b \xc4\xbe\x99\xd4\xdb%\xd0V\x0b\xbd\
+\xb8\x18\xda\x88\xba\x9f\xe3\x11-c\x9b\xf8\x9ci\xca\xc1\
+38z\xacl\xebM\x1b\x97\x08\xf5\x07\xa3\x1b\x7f\xd5\
+F\xc4\x96\x99=\xe2\xc50\x94v\x90\x8e\x8e\xab\xed\xb0\
+ik\x94\xa8C\x0b\x9bG\x16\xa2akD\xb0\x1c+\
+\xa9%\xca\xc2c\xa5\xa8\xe4F\x91\xd5&\xc4j\xe9\xc2\
+{\xb2\x9b\xd7\x83\x8e\x92K\xc1\xba\xcb\xde\xaa\xbd\xeb\x85\
+e5\x83\x91LKg\x22\xd7\xdb\x1f\xa7\xb0\x19\x9di\
+n\xeb,+\x85\xe3\xc2[fh\x19O\x13\x83 Y\
+#\xd1\x80\x90\xdd\x17\xd1\x84\x93\xd9\xb6\x91\x0c\x18D\xf1\
+\x96.@\xb1@\x88\xc6\x8a\x14\x1d\xa9\x09\x18\xc9\xa4E\
+\x1dY\x5c;(Kz\xec\x90Tr\xc5\x0dR\x8a\xb1\
+\x16\x89.\xde\x832\xcc\x13J\xa2\xe2\x80T[\x00\xcd\
+\xa8oSjra\x1a\xec =\x86H\xcc\xa5u\xa8\
+!\x89k~ j\xd2\x0b\xd24\xb2\x9a\x9aH\xb7\x02\
+\xbc\x1a&J\xce\x9b&\x87\x83\xea@\xc3\xccc\x91\x0d\
+P\xb2\xb4\xb4F\xa2\x89sZ\x14@\x94\xcc\x1d\x02\xcc\
+\xc8t\x14\xd9,\x12bD\xbe\x9f*\xfb\x80\x19\xa7\xdb\
+;Q\xa47\x80\x17\x93hv\xd9\x9b\xfa\xeb\xec\x87\xe9\
+<f\xbf\xd1\x10V\x06\xbe\x08[\xd9u\x01f=\xc0\
+le\xbe\xc0\xbaH>\x8aX$w\x17T\x87X\x8f\
+t\xb8T\xa3\x7fe\xd5WS\x8cu\xc7\x91G\xdd_\
+i\xb0\xc8USch\x0e\xfe4\x1dx\xd0\xca4D\
+XA\xfbC.~=\xaam\x9a\xf2\x89\x12\xcbQ>\
+VT\x8f,\xa0\xf7ao\x22\xb2H\xe9E\x95A\xd4\
+H\xef\x11+Q\xfbln\x83\xa8%\x0ch\xddQ\xb2\
+\x11b\xc9V\xe4\xae \xaa\xf3\x15E\xe5CD5\xe5\
+\x02X\xbcD\x0d\xf0Ej/\xaa\x968%\xfc\x80\xd4\
+\xff\xab\xd1\xbf\xb2\xbe\xafD\xad;\xfaY\x15\x1ffU\
+\xf9\x0a\xa2\x06\x5cQT\x9d\x11u\x87\x85\xe3] \xa1\
+\x0dqG\x8f\xb2\xa6\xac.A\xc0\x0e\xcch\xba\xcb\xf0\
+\xae\xe2v\x81\x8cF\xbd\xadG\xactSq\xce:p\
+w\xdcis\x8f&\x10pW\x15\x17\x88\xef\x83\xf8w\
+_\xec\xad`Yp;\xba\xbb-\x08*>\xd7\xdf\xbd\
+\x01\xe7\xcd\xe9\x9b\xe5\x10\x5c\xce\xde\xbdZ\xde[\xfe\xbc\
+\xec\x92H}\xf0\xf3\xec\xf4\x9f\xcbM\x0d34\x87w\
+\xb1\xef\xe1O\xbf\xae\x81\xe2\xae{\xf7\xf3\xde\x93w\xe7\
+\xe7\xdb\xd8?\xba\xdf\x95\xea~_\xaa+nV\xe84\
+t\x15\xf7\x93\x82\xbc\xd6\xfes\xa1\x8c\xfa\xbc\xe0\x0b\xe4\
+\xfa\xab\xd0\x99\xfag\xa8\xf7\xae\xbb>\xfe\xf7]g\x8c\
+\xc6j\xaa\xa3+\xefv\xf9\xbfME|\x03\xcb\x89\xcf\
+\xb4\xfc\xba\xbc\x98as\xbd\xfd\xc7\xaa\xd9\xa7f\x9b7\
+\xa12\xdf\xad\xff\xfe\xac\xe0\xbf\xa8\x0a~\x9c\x7f\xc3\xcb\
+\xe7\xbf\x1e\x9b\x02~\xcc\x81\xc6\xb7>\xbe\xa0\x1f\xed\xe7\
+\xc0\x02\x8a\xcd\xb3w\xc0]\xc6\xf5\xd6\x97\xb9\x1c(M\
+]]\xd8\xc0\xbd\xc2\xfa\xad\xcf\xb1 \xb8qay\xaf\
+\xb0y\xebK\x5c\x12\xcc\x0b{\x81\x80\xbaO@\xc7[\
+\xbf\xcb\x85\xc0\xa4\x8e\xff\xfc\x95\xf9e\x0b\x87\xa9\xcey\
+\x87\xfb\xb1\x93\x0c\xa8\xae\x1f\x08\x916&3\xb3E\xc5\
+\xcfI\xb3\xc8~\x09\xab\x91\xaf\xb6\xde\x1c\xe8?%\xba\
+\xf3\xe5\x90W'O\x96\xafV\x9f\x1c=\xaa\xbe}u\
+\xd5\x9d2*\xa8g\xd5\x0f\xdcx\xd1\x07\xec\xa8\xe5\xea\
+\x10\xe9\xf7\xdf\x86\xfdMU\x8aV\xb2\xad\xf2\x0b\x9b\xa3\
+\x98\x84,\xef\xd0d\xe7\x86X\xf4\xb2\xc0\x9f\xa0dL\
+\xf8\xf5T\x9d\xa3\xc0\x17h\xd78v\xb5[\x14M3\
+\xd3>J\xc7g\xf5\xd1\xc85\xda+\xfc\xd5\xcb\xee\xcf\
+=Yc\xcfN\xba\xcf:\x9f\x9d\x9d\xbc\x1fX\x1b\xd0\
+\x8b\xabYe\xbe=\xf5\xef\xf0\x16U\x80\xd0\x10\x9a\x00\
+R\xd2\xbbf\x03\xb2d\xad\xd8\x8cn\x08X\x183\xa7\
+\x0f\xf5}5\xc3\xb5\xac\xb0Z\x06\xd5\xeah\x904U\
+@\x91\x85a3\x16\xa4\xec\xb0\x85Q\xf3\x100\xee\x1b\
+\x15$\xea\xaf6BM\xf6\xed\xbb\xac\xb1i8\xae\xe8\
+zC\xaaQ\x861Q\xab9\xa4\x0c\x07H\xe3\x0e\xb3\
+\x06aX\xb9\xb31\x93\xb0\xf7Xy\x8eV\xd9\xe1\x18\
+>\xdc\xaa\xc9=\x8f\x89\x0dA\xc1\xeaBiINZ\
+E-\x00\x98P\x87qS\x0e\xc2\xa3\xacF\xe7h\xf5\
+\xa2\x88#\xe9\xd0\xf0h`C\xa3\xb7P\x1b\x84\xaf\xd1\
+(\x13\xd8\x17\xae-\x91\xc3K\xa7f\xae\xc6\x059\xa7\
++\x17\xf3\x14H\xfd\x8d\x026\x08TiO\x92\xb9J\
+-pr\x89Z\x9ef&k\xd4\x80b\xe8U\x0e\xc8\
+\x22\xa0\xf4Qu\x1d7\x1b\xe6\x80e \xb40\x19\xfa\
+HV\xecVC\xaa\xfc\x1c\x89I\xf6\xf2\x81o\x06\xb5\
+\x85B\xaf\x87m\xe6\x14\xd7\x0a\xdb\x08\xb1P\xea\xf5*\
+6\x8aZ\xd8\xa0\xff\x84\xd6\xdf\xb5Q\x93dK\xf6U\
+\x83\xb3Y\xac\x1bX\xb1}P\xb9\xa0/j\x16\xd0Q\
+\xa9\xa6F5\x8c:\x8c[x\x04a\xd1\xf5\x9e#\xe4\
+a\xf6\x0b\x01\xe0p\xee\x8d\xd2\x11\xa3&?\xd5\x99\xca\
+ Z\x9a\x91\xf3h\xdb{\xf6\x89X17\xe0\xf9%\
+'\xb1v-tv\xaeS.\x1a\xe4\xd0q\x07\x1b\x22\
+\x06\x92\xdc>4\xf9\x12\x1b\xdc\xfe\xe8XR\xde=\x0d\
+$\xf1/\x09 \xd3@QN\xe3 Y\xe5zH\xaa\
+\xac\xd6\x0e\xa8\xa8\xde\x17\xfa\xc8i\x89e\x19u\xa1\x16\
+\xc6\x22\x8e\xa9\xbdk\xba(vP\x92+A\xbf'\xe0\
+\xe5\x10\x84}\xf40\x16\xc0\xb2S\xb4f\x04\x99T\x01\
+D\x14\xdd\xec\x08u\x08\xe7\x5cq\xc4\x12$'\x98\x94\
+\x1d1y\xdd=\xa2\xda\x18\x01\xd5\xb7)ZS\x89\x08\
+\xdf\x1e\xdb\x1b\x9b\x19\x97en\xd8D\xcc\x06\xce\xc8\x83\
+S{\x04K.\x90\xa0!\x84D)\xc3!\x01{\x88\
+\xd2@\xfa\xd5\xad (\xf77\xab\x07\x944)\xc5\x0f\
+B\xa1\xd1\xc2\xa0\x0a`k@.\xa4\x1dV\x83s\xac\
+03\xf3>P9X\xd4jmDK\xd1\x09\x046\
+AC\x9b \x80\xc4\x04\xf5l(\xe1\xa8\x13T\xa2\x85\
+brN\xd1\x8au\x8cN\x13\x94\xbd\x05\x82\x88OP\
+\xa4F\xc9AYr\x15\xeahT\xee\x86\xe4lz\x94\
+\xda\x14\x1c4\x16X\xfe\x19\xa1Z\xf2kbT\x81\xdb\
+0-Hu\xd8107G+\x13\x09\xf14\xaah\
+ \x22fe_\x12F\x94\xfbL\xee\xb7\xa3\x1f*B\
+\x19\xf41\x82\xb0\x91\x04A\xc94\xa2BMTSK\
+&\x8b\x96\x92\x01\xb2\x85\x1e\x17J\xe9\x06\xba\x85\x9a7\
+wR\x89\xc2\x92\x8d\x93Gl\xa2\xa7\x11\x1d\xf5\x7f\xbc\
+\x8dZ\x03\xb0\xa0\x18\xc7)L\xc2\xc9|\xe4h\xc4\xb6\
+\xb9\x9fA\x11\xac\xb9\x92\xf4\x097\x1a\x91\xa0\xe0\x96\xe5\
+\x7f\xbfO+\xfb\xc2\x1e\x03]\xbe.\x0a\xfdz\xf6\x0d\
+46\xfa\x92C\xd7|\xedc\x81\x97\xd4>\xae\xa99\
+\xd4>\x12\xe6\xa5R\x06\x02\x95\xc2(8%\xaa\x0e1\
+5\xd2\x82\x5cWz'-\xa5{\xac2_%\xa0\x9e\
+\xb0V\xd7PpD@jT\xa63\x0f\x8f,L,\
+I\xfbL\xe7I\xa8yC\x99\xce\x14o0\xd3\xcd\x17\
+\xcd\xf3\xc9O\xfeL~\x7f&\xbf\x9bI~!\xcd,\
+\xc5\xae7#\x16\xda\x81\x98\x7f\xe6\xc9\x7f\x93<\xa9\x90\
+c\xac\xdb\xed\xb4\xd0\x9d]2\x1c3\x89\xe3\x87\x99\xc4\
+\xe1\xc3Lb\xb9\x93I\x1cv3\x89\xebn&q\xfd\
+0\x93\xb8~\x98I\x5cv3\x89\xcb\x07\x99\xc4\xe9\xc3\
+L\xe28f\x92\xd9\x18\xcf\x17\xd6\x07\xf6\xbb\xaf\x0f.\
+\xcf\x93w\xc6D\x89\xd8\xdc\x16H\xd1\x22\x5c\xf8*\x8b\
+\xc18Lc\xd7\xbdO9\xda1I\x93\x95\xb7\x80s\
+y\x8b7\xab\xcd7\x17a\xce\x0d\x00\xd1H5\xb0\x03\
+\xa6\xb7\xecq%b\xe2\x02/|'\xe7\xf2\xba\xe2\x22\
+\x93s\xf8}\x9a\x9c\x13\xed\x94\xa4\x88\xadwx\xcd\xf5\
+6\xca\xf6\xe6Z\xacv\xc9pks-\xc6\xbd\xb5z\
+-\xfde\xd0?p\xdca\x1bo\xdd\xdaa\xcb\xed\x0d\
+6\xe4\x06\x8c\xd4!\x9b]\x1b\xd4\x86j\x05mv\x93\
+\xa6\xfc\xed\x0b\x9c\x0e\xfa)^\x94\xcdBh\xde\x8b.\
+0\x02\xfaR\xbch\xd7i\xe6\xdcj\xf4\xa2\x01\xf0h\
+\xae\x98\xa1k@\xb22\x14\x1a\xedz\xe2\xfe\xa5\x1d\xc1\
+\x9c\xd6\x0e\xde\xc0\xde\x1f\xa8\x5cn\xefh\xad\x01\x8a\xb3\
+\xfa\x15\xb57\xef\x1a\x9c6u\x8da\xdb\xb0\xf6:\xa9\
+\xdf\xe5\x9c\xee\xce\xc2\xf0Wb\xd5a{\x15\x94\xf2\xd1\
+\xa6\x09-\x093E\x17w\xb21\xd8P\x05\xb6L\x12\
+\xb2\xbc=_\x1bD\xea'\xf2}Csg\x9fa\xee\
+>]\xd1\x87gS\x8f/9\x0e(c\x09h\xdc\x12\
+\xd9\xb8\xf6\xc1\x19\x1b\x93*\xf5\x8b9w\x12\xa7#\x8e\
+\xa6\x12\xea\xd1\x87pN\x009\x12k\xa0\x89\xe6\x1b\x8c\
+\xab\x9e\xc6\xa6NA\xb8\x85\xba\xb6d \xcc\x1a\x87\x0c\
+3t`F\xb3%\x84\x13_-\xc2D\xfa\xe1\xf3\x11\
+\xf0\xc5\xceGXs\xac\x9cG\xd0\xd8\x83p\x1b\x93h\
+!\xe2\x93\xeb4\x1b\x1bR\xe4P\x8a\x130\xc1\xb0.\
+\xb7\x00\x8f\x9a\x0c0T\xebS\xa6\x81\x22\xf3\x91hs\
+\xa3D\x1f\xb1\x9a\xf4h\xc6(l[(W\x0eL\xd7\
+\x1e\xc3 \xef\x98$m\x14\xe1Z3\xc9\xa9\x80\xf2\x07\
+\xb0\xa3D\xb8\x82\x1d\xd1\xef\xcc\xaf)\x1a\x12e`_\
+?\x99\x1by\xcdQ\x88\x93da\x96AaG\xac\xcd\
+\xd4\xb5\x90$\x02\x8b\x9aKjh)\xe2\x85:\x889\
+\x17=W\xa0,\x885\x89\xcb8\xa4\x0f\xa5\xfd\xb8B\
+\x22\xb1Z\xe1z\x14Je\x8e\xe9\xa0\x13T\xb29$\
+jNP\x83\x06J\x1e}\x01IM\x18\xb2\x0c\x11\x1b\
+9\x93\xe2\x91{\x0b\xc2@*sgB3\xe9\x17\x90\
+\x988\xc8\x8d\xac\x0e\xabO\x88\xa0B\x9a\xd4\x95\x14\x0a\
+)G\xc1\x0dB\x98\xa2\xa7\x08FAW\xb0\xa4\xa3\x1f\
+\xf6+\xcb\x9b\x00)p\x99.\x90\xa8\xea\x11gC'\
+\xd5,\x0c\x01\x1d\xfdH\xa0\xa5:\x04\xf7\x98\x92Z\xef\
+6\xd9\xaa\x97\xa2PH\x87\xa4\x81\x22*Y\x8f1\xb8\
+\xe9\x9e\x91\xf7Zvn>\xcbQ\xff\xea\x87`\xbe\xf9\
+\x7f\xaf\xd7Z\xe4TM\x01\x00\
+\x00\x00\x17\x91\
+\x1f\
+\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xed=io\xe3F\x96\
+\xdf\xfbWp\x9d/i\xacH\xd5}\xb8\x8f\x01f\x82\
+\x04\x016X`&\xc1\xcc\xb7\x80\x96([\x1bY2\
+$\xb9-\xf7\xaf\xdf\xf7\x8aW\x91,Q\x94,\xbb\x03\
+\xc7v:\xa6\xaa^]\xaf\xde\xcd\xaa\xa7\x8f\x7f\xdb\xdd\
+.\xa2/\xd9z3_-?]\xd0\x84\x5cD\xd9r\
+\xb2\x9a\xce\x97\xd7\x9f.~\xfb\xf5\xc7\xd8\x5cD\x9bm\
+\xba\x9c\xa6\x8b\xd52\xfbt\xb1\x5c]\xfc\xed\xf3\xbb\x8f\
+\xff\x15\xc7\xd1?\xd6Y\xba\xcd\xa6\xd1\xc3|{\x13\xfd\
+\xbc\xfcc3I\xef\xb2\xe8\xfb\x9b\xed\xf6\xeer<~\
+xxH\xe6Ea\xb2Z_\x8f\xdfGq\xfc\xf9\xdd\
+\xbb\x8f\x9b/\xd7\xef\xa2(\x82q\x97\x9b\xcb\xe9\xe4\xd3\
+E\xd1\xe0\xee~\xbdp\x80\xd3\xc98[d\xb7\xd9r\
+\xbb\x19\xd3\x84\x8e/j\xf0I\x0d>\xc1\xd1\xe7_\xb2\
+\xc9\xea\xf6v\xb5\xdc\xb8\x96\xcb\xcdw\x1e\xf0z:\xab\
+\xa0q6\x0f\xdc\x01Qk\xed\x98\xb01c1@\xc4\
+\x9b\xc7\xe56\xdd\xc5\xcd\xa60\xc7PSF\x08\x19C\
+]\x0d9\x0c\xear\xb7\x00T\xec\x9d\x8c\xab\xf5G\x07\
+\xf4\xdf\xc1\xbf\xaaAY\x90lV\xf7\xebI6\x83\x96\
+Y\xb2\xcc\xb6\xe3\x1f~\xfd\xa1\xaa\x8cI2\xddN\xbd\
+nJ\xec7\xc6ml\xc92\xbd\xcd6w\xe9$\xdb\
+\x8c\xcbr\xd7\xfea>\xdd\xde\x0050\xe3>\xded\
+\xf3\xeb\x9bm\xfdy>\xfdt\x01\xeb\xe3\x82\xe4\x9f\xcb\
+\x19\x5cVtD\x12\xcer\xd0\xa2[\xbfJ\x98\x84F\
+k\xab\x15q \x0d\xe2kt7]Mp\x86\x9f.\
+\xbe\xaeV\xb7\xf1\xea~\x9b\xc0\xa8_\x9b\xfdB\xe9\xdd\
+\xfd\xf6\xf7l\xb7\xcd\x96y7\xb00o\x95\xae\xda\xb5\
+K\x1aK\xac:\xc8vw\xab\xf56\x9e\xcd\x17Y>\
+\xd8\xf8fu\x9b\x8d\xef\xe6KX\xf6z\x05\x0f\x93\xcd\
+x\xb5{\xbc\xce\x96\xf1|\x02\x946\x86v\x8b\xf4j\
+\x91\x8d\xd3\xc9v\xee\x0an\xd3\xc5b,\xccN\x98q\
+5\xd5\xbb\xe5up\xa0\xdd\xf4\x0e6\x96r\x19\xac}\
+\xacj?C\xf5\xc7i6\xdb X\x8es\xfc\xc4\x05\
+%\xae\x0ej\x81l\xb2t\xfd\xd3:\x9d\xce\x81Yr\
+8\xaf\xcb\xc9j\xb1\xc8&\xb0o\xe9\xe2!}\xdc\x5c\
+T\x00\xd0U\xb3)\xb7T\x15\x9dB\xb7\x9b\xed\xea\xae\
+\x84\x85\xdd\xd8>.\x00+X\x18C\x8f\xab\xf5\xe5w\
+\xf4\x8aI\xce?\xb8\xa2\x15\x90\xcf|\xfbxI?\x5c\
+\xd4mV\xb3\xd9&\x83\x81\x89W\xe6\x88\x06Z\xc0X\
+ R\xc6O\x1b\x8d\x84F\xa3\xc1\xd1\x18\xa9F\xfb8\
+n.\xfbiht\x5c{y\xb3\xce@\xca|\xf7\x9f\
+_\xfe\xe7\xe7\x1f~\xb7\xbf\xc7\xaa\x07\xcd\xccP#\xaa\
+\xfa\xeb\xa2\xf4\xb7\xe5|\x0br\xe4~\x93\xad\xff\x85\xbc\
+\xf8\xbf\xcb\xdf6Y\x07\xea\xd7u\xba\xdc\x00\xe3\xdf~\
+\xba\xd8\xe2\xe3\x02D\xef\xf7\xcc&Vq%\xed(\x06\
+\x92I\x94b\xf2}=?\x0a(\x11\x168\xd1\xaa\x1a\
+5\x8fPjd\xc2\xb9\x10\xa4\x9e\xcb\x8e\x01\xac\x14\xd8\
+\x83\xf1`\x99\x0f[aq\x0f\xbe`\xb9\x01,\x0c[\
+%\xce\xd5\x8a\x84\x0bn\x08o\xcc\x95\x12\x06\xc5B7\
+\xa6jT\x22\xb9\x94\xd66\xa6\x0a\x1dHD\x86\xd9G\
+\xca!\xb2\x0c\x10\x9c\x9c\xe0o\x0fy\x97\xc4\xa5X,\
+\xf7\x93r\x09\xa5\x85f\xf1\x81!\xb3\xd9\x8cd\xb3!\
+\x1c\x95p\xca\xadPz\xd8\xc0$\xa6\xfd\x03\xa7iz\
+\x95\xdaA\x03k\x06RB)\xbb\x7f\xe0\x10#\x86\xf0\
+\x0b['\xe9\x10\xfc\x0a\x0f\xbf\x7f\x06\xe6=\x96\xac\x03\
+\xcc{\x9bn\xd7\xf3\xdd\xf74\xb1\xf8c\xe8\x88\xc0\xaf\
+\xca?Y\x09|\xccXB8cz\x14+N\x81!\
+-\xb3/\xc0\xd38\xd1t\xf1,hlv\x8dh4\
+gC#\xe0\xca\xfd\x18\x87\xc6\xe2\x13\x05,\x0a\x05\xeb\
+\xe6\x14\x1f\xa9\x86\xd5r]#q\xb2C$\x22\x00\xf3\
+$\xc8\xe4\x11\x0d\x1c\x82]\xd0\xbat\x16\x84\x9d\x05a\
+\xd7\x9f.\x10\xb1`\xf9\x1c\x12\x95G\xa1\xb5\xd9\x87\x16\
+\x96\xf5S\xa9%OG\xef\x1e\x15c\x90\xf0(o\xd3\
+\xa3N(Umj\xd4Fs\xd3\xa6F\x93hi\x0c\
+oP#\x85!\x18\xb7\x034\xcc\xf1\x86\x8d\xc3\xd6p\
+Sc\xe6~N4l`,q\x94a\x13\x1am\xb0\
+a\x03\xa3\xa9C\xb2\xf1\x1cL\xdd\xc2'\xa5\xa6\x9f\xb9\
+=\xea\x1cF}\xc8\x8dF'\xb2\xc1\x88`\xcc\x18-\
+\x89'\xcd\x90\x11\x8dM\x8c\xa0\x86\xcb\x06#\x828\x94\
+Z[\xdb`D\x0a\xa0\x9a1\xd2\x9dMW\x88\x10\x90\
+\xbeT\x12.\xc5\x08|(\xca\x09\x98\x1b\x84\x8f\x8aG\
+\x94-\x08 \xa4\x02i\xc2\x13\xcb\x15e\x9c\x8f(\x05\
+\x8dH@\xb6\xbe\x1fb\x19\x05\xd08\x9cP\xa6|6\
+\x19D(A\xb2\xa4\x9e\x05\xbc\xdfV(}\xbbV\x87\
+\x89\x94 E\x89\xc7\xc8\xc1\x19^\xa539k\x99L\
+$a\x80G`w\xf6a\xd0\xf8*8\xbe\x96R1\
+\xea\xedcp|\xc3\xafdv\xd5\x1e_X\xb0&-\
+\xeb\x1b?h\x9e\xe8\xd9D\xb5\xfb\xd2F\x08\xc3\xb4\x19\
+\xcc\x9f\xa0\xc8\xbf\x01\x7f\xc2\x0c{\xf8S3o#\x9d\
+\x1a\xd4 \xbbA\xb3\xd1\x06\xf7\x09\x96(\xa9%k0\
+_\x17t\x16\x02\x05\xde\xe3,\x91\x94i\xd5uuB\
+v\x90\x06\xfa\xe29\xbbY\x0e\x8c!\xb4\xe3B\x0b\x9e\
+\x00\xb0\xdc\xc8\x01X\xc58\x9aF\x14\x14\x856\xf0\xa8\
+$\x10&h\xf6\xf7\x03\x85\xcd3h\x16\xc4\xf4p\xa2\
+\xca\xcd\x94S5\x0b3=,<p\xb4\xe1\x9a\x85\x99\
+\x83\x94;\x9b/\xb6\xd9\xba\xa2\x19\x1c5\x9e/\xa1\xe8\
+n\x05V\xc3|\xb5\x8cs\x08\xd8\x89\xcd?\x7f\xfa\xfb\
+\xc5Q\x88\xce\x9b\xc24\xbc\x98\xc4,\xfb)\xbd\xdfl\
+\xe6\xe9\xf2\xef\x8b\xfb\xb57\xe9C\x1d\x22~\xa6?d\
+_\xe6nZ(Q\x94\xd2(\x7fuk\xe9\xcd\x11`\
+t\xe3!!\x9f\xd2\xb3\xb1-\xf8\xbd*\xe6\x9e\x93\x18\
+`]\x11\xd0e'{\x1f\xce\x5c\xa6h\xbf\x0aC\x14\
+<\x03\xcb\x81\x024\xc0\x5c\xa2e([0\x00\xad\xa6\
+MC\xd9\xaa\xc4(#\xa9l\x8a\x88\x0e\xec,\x08\xdb\
+\x90\x11\xe7g\xcd\x0a\x9b/d\xf8a\xd4\x22\x96q\x8f\
+c|n\xe3\x0f\x9d7\x18\xf1`d\xeb%\xd8T\xd0\
+\xe7`Sp\xe5\x8c\xe5\x82\x9a~.\x15t/\x97\x9e\
+/0@\xc9\xef\xb1\xe9\xa17\xb4z\x8f\x0d\xeb9\xc7\
+\x09\xb4\x98\x12\xc6c\x0ct\x9d8O81\xcc3r\
+\x9d\xebdMB\x0d#\x1e,s\x06\xb1\x92F\x0d\x0f\
+\xcd5\x97rDl\xae9G\xea\x05\xe9\xcax\x9cQ\
+\xd2\x93Pe<./}Z<\xeeG\xf7\x13\x8a\x0f\
+\xd9X==\x1a%\xc1~\xe1\x81\xde5=\x1c}\xfa\
+6\xaa\x80\x1d\xedd\x9dG\x15<\xaf\xb1\xf8\x9cA\x13\
+\x22\xa8\x17\x09\x0d\xb3\xf0\xb1\xc1\xbd\xcd\xdd:K\xa7\xbf\
+d\xdb\x9b\x15nQ6\xc3Y5\x19\xdc\xf0D\x11\x22\
+\x9b\xb1\x11@\x0d\xe1\xe0D6\x19\x1cX;\xe1hy\
+\xf9\x1c\x04\xd60\x9a+'8\x98\xf9\x82_*\xf2A\
+\x04\x8f{b\x1f\x1e\x9c\x8de\xa8\xd3\x84\xe6\x01P\xd5\
+\xcf\xab{\x94\xe6\xcb\x05]\xc0%\x01\xb4\xfe\x09\xb4.\
+\xd3\xe2Y\x8ccj\x19\x15D\xb1\xd6\xe2\xdb\xc6\xb1V\
+\x7f.\xe3\x98\xdb\xf3\xc5\x94\xff\x94\xc6\xf1\x8bXr\xec\
+\x99hJ\x0a\x05\xfe\x94\xed\xa7)\xc1\xf6\xd2\xd4\xf9\x15\
+B\x90\xa6\x9a J\x883\xbc\xab\xad\xc2\x1c\x84\x81&\
+\xe0\x18K\x04\x85\x00\xea\xd1(GVDr\xc2\xb4A\
+r\x93DK%G\xb1P\x09W`\xd8b\xc4\x9da\
+\xc0\x1dTf+\xe2Nh\x229\x15\x0d\xb5BM\xa2\
+@\x89h\xdaP+]P(\x94\x00J\xa1[v\xde\
+\xf7?-\x15\xc4)\xebeY\xcf\xb6G^\xd2\xf8J\
+\x0c\xd4p\x93\x97\x04\xe2\x881B\x1b\xbc\xd4\x85\x9d\x05\
+a\xeb72\xc36\xf2\x19\xc2D\x88\x85\x97R\xc3\xb8\
+\xcf/\xa7\x0b9\xfd\x16/ \x0eQ\x15;\xe5\xfd\xc3\
+\xf3\xd2\xde\xd1\xd6\x1b7V\xc7:\xe6\xfb\x08\xa7\x0a\x03\
+\x18kc\xd1x\xc5?\xd0\xa5\x9aM\xf0\xb7Eg\xc7\
+\xd1\x8e\xc1\xdfv\x0f!\xd3N2\x06\x0e\x96n{\xf2\
+\xf9\xe9\x1c\x02NV\xac\x0f\x9b\x8e\x00\xc9c\xb6\xc7x\
+\xd4\x8cs\xad\xa5=\xb0f\x92\xcd\x02g,\x86\x0c-\
+]x'4\xb4\xb1\x84\x09\xdf\xcf\x09\x1f\xef\xe0\x19\xcd\
+\xba'\x1e\x86\x0c\xada\x83CoF\x0e\x8c8\xc9&\
+W\x93\xab}\x1b|\xdcY\x8a\xae\xb7\xc4\x81\xfa\x0fL\
+\x9d\x09r\x02]\x12\xab\xcc){\x04\xa3\xf1\xe3\x91\x94\
+f\x93Y\x87\x0b>\x9c\x0bKBR\x036\x86>\x84\
+)!\x19\x89i\x98\xb4\x0f\x90U\x96\xc1>?\x89\x8b\
+\x05\xfe\x0e\xe1b\x91\xbfS\x08i\x02i\x15\x8a!~\
+x\x9b`\xa9,\xb6q\xe8M\xe3\x81\xad\x9a\xa9\x99\x9c\
+\xc9\xf3\xd0\xf3S\xecFK\xfb\xce\x08\xe1\xcb\xc6\x86\xa5\
+\xa68*\x0b?t\xefB|x\x22E*\xaf\x14M\
+\xb5\x00,\xcbc&j\xf0\x89\x99g\x8c\xa1\x1c\x5c\xba\
+\x17\xb1\x1c\x1eX|>\x04\xeds\xec\xf0\xb5\xb0;z\
+%\xd0\xcb3\x18_1D\x1f~\x89\xff\xac\xa8\xb3G\
+\xa2\xae\xef0\x03\xe3D+ \xc4\xf6jc)\x13j\
+(\xd4\x8e\x18b\x12\x96m\xde?\xd3f|Kd\x0a\
+\xfe\x5c\xc8\xa4\xc5i\xb3\x06.1l\x07\x980\xf4U\
+\xe2R\xbf(.\xe3\x22\xe0I^%2%}v.\
+\xe7\x0dlZ\x89\xe7J\xa9}}\xc8\x14D\x9e\xf2\xc6\
+\xed\x95,\xfd\x8c\xc7\x90{U\xe2+D\xdd\xf9\xc2\xc4\
+\x7fuE+\x88:\xc3A\xe37E[\xe0\xf2|o\
+t\xff\xea\x8a\x16\x90y\xbe\xc0\xfd\x9b\xa2Uo\xda\xe6\
+d\xd4\xbdi\x9b\xf3!S\xbfi\x9b\xf3\xe1\xf2M\xdb\
+\x9c\x11\x99o\xda\xe6\x8c\xc8|\xb6\x80\x83\x87L\xa1\x12\
+*\x99\xb2|\xe4.B\xbeN\x1e7/ /kD\
+\xc6\x94\xe3\xcb\xce\xd7\xc9\xe1\xe6\x05\x22\x8a\x1e*\xad\x82\
+RA({\x95\xb8<\x9f9\xb9\xdf&\xf2\x90\xa9\x11\
+?\x8a\xda\xd7\x89\xcc\xf3\xbd7\xe8\xd8\xe61\x1e\x1d\x02\
+\xe98\x8a\x0d\xae\x14P\xc8_#\x0a\xcfx\x94\x9a$\
+\xdc\x08E%7m\x5c\xeaDZ\xa6\xa5\x10#\x87\x1e\
+\xf2:5\xce\x19\xcf`\x0eAeI\x97\xe65\x1aB\
+\x94\x9c\xd3\xaa\xdc\x87Lf\x12\xcb$\xfc\xbcf\xba\xa4\
+\xe4\x9c*\xe70*_9]>\xff\xab\xea\xbf\x8c\xb7\
+C\xe99\x95\xcf_\xdc\x0f\xa7\xf4\xd8\xf3'o\x01\xa2\
+\xfd\xb8|\x8b\x5c\x9e\x0f\x99\xec|\xef\xfdi\xd2\xc5\xa2\
+I$\xe7\x94Z\xf3\xaa\x83\xe9\x94\xfde_\xf8S~\
+,\x01\xbd\xd8\xc9\xba:O\x14\xe8\x16w\xbfiD\xbe\
+\xe5Q:\xc0\xd5\xf9b5!f\xa3\x0c\xd9\x8dP\xf6\
+R\xcc\xf6q\x8cY?\xddS\x95\x17\x15\xf3\x94N\xbf\
+\xcc\xb3\x87w\x15\x1a\xae\xd2jIw\xe9u\xe6N\xcd\
+\x02\xf2\xf2\x1b\x1eE\xc5\xd5j=\xcd\xd6e\x95r?\
+\x8d\xaa\xe2`m\x9d\x89\xd5\xdb+\xec\xb5\xaa'\xe1\xfa\
+\xcdM:]=|\xba`\xedJL\x8a\x0a\x0bk\x17\
+\xe3\xd5\x0b\xa1\x13\x0b\x9ec\xa7\x09^\xc0\xd0\x98F\x16\
+\xdc=\xda\xae\x9c\xae&\xf7\x98\x1f8\xbe\xcf\xb7\xf6n\
+\xd7i~\xbf^#\xc0\x22}\xcc\xd6\xcdl\xb5u>\
+[c\xaa\x86E\xc6[\xafds\xb3z\xc8\xd1\x82d\
+~\x9f\xb5G\xc0z\x7f\xd1\x1e\x0cV]\xafq[B\
+\x0d\x1f\xe6Kh\x10\x979v\xa9\xec\xac\xbd\x80(\xa7\
+\xa9M\x07s\x05\x04\xe0O\x8a}\xcd\x1f\xf1^\xbe?\
+\xa3\xfb\xf94\xdb\x84\xe7\xe4\xea\xe2\xab\xab\xd5.\x5c\xbf\
+\xba\xfa?`\xd4\xf8.\xdd\xde@\x0f\xb3t\xb1\xd9\x07\
+\xb2\x5c\xb9A|\x90\xbcf\xbbZd\xc0b\x93\xac>\
+\xeb\x8d8\xf2\x8bM\x83\x1a\x8b\xad\x0b\xe2~\x99\xde\xc5\
+\xd7\x8b\xd5U\xba\xe8\xc5\xf1m\xba\x9b\xdf\xce\xbff\xd3\
+\xfa(}\xb3\x0fo\xc5\x85\xc8\xaaQ\x02\x93+\xd9r\
+\xfb\x88Y\x94w\x8fX\xd6\x90>X\xc0\x84\xa8-O\
+\xcc\xa6<_^\xef0\x83\x05\xf2WENU\xd5c\
+\xa0*\xbb\xbd+jk\xe6\x89\xa2/\xf3\xcd\xfc\x0a\x0f\
+\xc2{+\x04\xd8%\xe6\x1e\x9e\xb6Jq5\x05<\xce\
+\x09\xa5\xe2f\xb5\x5c<\x16`\xa5,\xe9\x8a\x10W~\
+\x9bm\xd3i\xbaMkyR\x96p\x90\xa8%j\xd6\
+\xd3\xd9\xe5?\x7f\xf8\xb1:\xe3?\x99\x5c\xfe{\xb5\xfe\
+\xa3\x9cB\x14!@z\xb5\xba\x07\x9a\xad.=`\x12\
+\xe3\xc9%\xca\xd5t\xfby~\x0b\x0c\x83\xa9\xb1\xff{\
+w\xbb\x00\xc9VU4\x80\x11\xdbu\xa7y\xb7\xeb,\
+O}\x1d\xcc\x16>\x9d\xdc\xce\xb1\xd1\xf8_\xdb\xf9b\
+\xf13\x0e\xe2\xddE(:\x9do\x17\xd9g7f\xfe\
+X\xaeb\x5c,\xa3\xbcI\xe0\xad\xf2\xe3\xb8D\x83\xfb\
+t]\xa3\xe7Z\xab\xeav\xe86\xa4\x0eM\xa2\xf16\
+'S\xa3\x18\xf3yf\xb1z_\xa2\xf1\xba\xa2\xaaP\
+xA\x08\xa6\x18z\x1a\xa0}\x0cxj\x98\x01\x8bY\
+\xc9a\xc0\x91\xab\x96V\x13\xcc\x13Jt\x02\xda\x87\x83\
+\xed,y\x22\x89\xf0#\xdc\xf9\x14%\xf1R\xe0\xac\x81\
+\x05k\xa4\x167,\xea\xf4fVSB\x85d\x1ff\
+\x80\xc1K\xc0\xed\xf7-\xc5\xebr\x17\xbfw\xd5\xde]\
+\x99\xcdv\xbd\xfa#\xbb\x5c\xae\x965)\x16\xf7\xf2`\
+<-\x94\x7f\x83\xa5\x90x\xad\x1b\x99\xb58\xc6$\x22\
+.\xd7\x97W\xe7rIX\xc0\x00o\xe4\x87\x03\xba\x8e\
+\xa5H\x80\xf5t\xa3\xab\x10J5\x81\xb5\x81\xa6\x1ey\
+\x8fq\xb8\x98\xf8\xd6K\x07i8(\xa8+\x85\xf1\x9f\
+\xf6\x14U\xa2\x98R*\xb0*\xeeR\xbd\xb2\xc6\xfd\xa4\
+R\xf6c2*\xc5;7\xa3s\xdc\xe9@\xce\xbd\xbe\
+\xddQ\x03w\xe7\xcc8B\x9d\xe0\xcd\xb3\x140\xb9\xc8\
+L\xd7\x93\xbeE\xe0\xec[\xa9a\x8f 1\x1cY\x0b\
+\xd3\xb8$U\x0e\xefn\xe7KD}\x83\x9c\xeaz\x97\
+\xc1\xd5\x09b\x13\xaa_\xef\x02\x84Z\xd7>\x06jQ\
+jFTj\x8c\x0b\x88Q\xd9y4\x8901\xad\x15\
+R\xc8\x08d\x017 \x18Fy\xe3(\xce\xffV\x1f\
+s8`\xf4\xaa\xa6lQ\x17\x14\xb0\xb0\x0d\xd5\xbfE\
+TT\x92\xe8kh\xba\x9bm\xban\xdf&+\xeb\xb2\
+%\xcc\x9b'TP\x8c\xab\x9f\x8fL\xd0\x1d\xa0\x84\x80\
+C\x10\x03sh0\xe3\xa4\xed\xe1\xad\x93\x04\x92%G\
+\x0b$\x1b\x10Hn\xa3\xa4\xd9\xcb\xbb\xfe]\xdf^\x89\
+\x14\x10\x0e\xe7d\xb6\x8f\xe3\xeb\xe2\xc1\xe7\xb9\xee\x084\
+\x91\xda\x12\xa6\xc0\x17\xc3\xc4\xba\x8c\x0b\xc5p\x80\xea\xb9\
+\x06\x88a%\x12s\x01\x80\xc2\xe1\x12<\x1b\xc6\xbc\x10\
+LN\xd1\xa0h\xb8flT\xe5du$Mq\x8b\
+$\xa5\x22\x8aMb@'\x19\xd0Te\xd2\xd5(.\
+\x1e\x1bEe\x0b$\xef\xaa|T67\x8d\xc2\xba\x1d\
+\x19\xd5-\xa3\x12\xd6\x07\x08\xb6\xf2\x07+\xe7R\x0d\xd4\
+\x9d\x5c\xcd6\x0d\x1e\xeff\x91m\x08\x88\x9e\xeap\x12\
+\xdb\x86xj$\xbd\xad\xe4\x99\x9fI\xf9\xb0\xbc\x04\xa5\
+?\x84\x03\x02R\xb9\x22\xaa\x1es\x04\xdc@%-\x11\
+.9\xa7\xa2`b(G\xa9\xd5s\x0d\x10S\x8e\xc9\
+9\x15\x03\xd3D\xa9\xc4p\xa2E\xc7 !\x0a\xd3\xff\
+\x0c\xd3\x1c\xb5_\xe1.\x88\xfa\xcc\x5c\xd6 \x1a\xee\xc1\
+\xd7\x88\xf1\x8e\xb9\x00S\x88\x89\x10\xd8j=\xbf\x9e/\
+\xd1S\xf8%\xa2\x86\xe2\x97\x0c\x80<u\xb9\xa8`\xba\
+\xd1?\x22\x0a~\xb8\x02\x863u\xa1\xcb\xb1\xee\xe0\xa4\
+J\xac\xe1\xc0/^\x99\x16u\xdb\xaa\xd0b\xae\x0e\x03\
+\xce\xaa\xd7\x1f0q\xd9a5p]\x06\xad\xadM\xc0\
+\xc4\x13\xcc+ex\x92\x862\xbf\xc3\xaa\xc8\x1b\xb8*\
+\xf3&X\xf5V\xaf\xa3\xbb\xde\xafQ\x03\x0d\xb2x\xc0\
+\xc9\x00A\xc2s]\xc6\xd0@q\x8d\xa4I\x84T\x1c\
+8\xa5.kL\xa6,\xb4$1(PL\xdd\x1d\x05\
+\x89\xe1/_8\x94KP9\xdc\xe4\x95\x92\xf9\xed\xe0\
+\x93\x8f`\xf8X\x8f^\xb5\xab\xe6\x18X\xca\xd7h\xb8\
+\xcd\x81\x19q\xfbX\xe8C\x9e\x88&oZ'&}\
+\x1f2E0+R\xdb\x1c(g7\x12\xa0cA\x1a\
+\x80\xec\x8c1!\xbd\xb1\xb9\x9a\x07\xae\x11\x0a\xcaGT\
+$D[N\x94WV>\xa0\xb8-\xda\x00\xb6r@\
+Z\xd7v\xe1\xbd\x11\xb0\x0c\xc7\x8f];\xa3@\xfcU\
+E^\xffnR\x96\x10\x85\x82\x1a ]\xe6\xa3\x1a \
+\xee\xb6\xf9\x1a\xdd\xe2\xbc\x12\xdc\xa6\x09lL\x82\xe9\x91\
+ARD\x0c\xb3t#,R\xa8\xa2\x04i\xba,*\
+\x1f\xb0e\xde\x02j\xdd\xd91Ex^\x8d\xa35\xe0\
+\xb1\xc0\x01s\x87\xb1\xbc(?pf\xa9\x22\xb4.*\
+\xa0q5\x0e\x9e[`\x0a\x04s_\xa7P\x8d\xed\x83\
+\xe7\x04s@a\xc30T\xa3\xd7\x95G\x03\xab\x8fT\
+b\xde2\xc9\xe8H%L\x1a\xe2\xbe\xaaa\xafi\x1c\
+\xea\xd9PM\x99\xa6\xb6\xe8\xb9\xfa\xc8\x81Z`i\xb0\
+\x070\x7fp#\xad\xd5\xef{h\x0b\x5cL\xcb+\xe2\
+\xb2`\xe6hG\x5c,A.B\xda\x92\xb0b.\xea\
+\xa2\xe2oNY\xd8@\xa9\xa8\x04\xab*\xdb\xc0^\xdf\
+X\x84\xe2\xc7\xd1\x954\xa0\x89\xb8WV\xf7^\xcc\x07\
+\xd4\x81\xa3+L\xe6m\xea\xfa\xb8\xdb$'+\x0e\xa8\
+\xc8\xe9\x0at\xa85\xd4\xd1\x15~y\x00\xd8\xd5 (\
+\xc0\xd91\xc5g\xf7\x7f\x5cF\x01\x88\xf4\x8b `p\
+\xba:\xd7O\x5c\xc3\xe6\x9f\x1d\xb4\x16\xd4\x11TQ\xea\
+\xd2-\x19\xc3\x0d\xc8,\xaf\xb0j\x84\x8b)\x9a\xf1(\
+\x07\xa5,\xaf\x97Q\x13\xbeIR\xb5\xafB\x02\x09\x1d\
+j\x93W\xe2\x11\x1a\xe0\x98\x0f{\x85\x95 \xbd\xfa>\
+$\xac\x04m\x0a\xab7\xad\xf8\xa6\x15\x036\x14&\xfa\
+\x07\xa5bI\xd0\x1b\x0e\x9bd{%\xdd!\xf1\xa4Y\
+G:I\xbeW6i\x16\x15 \xfd\x82\xc9\xf5\xda\x92\
+K\xd2*\xd1#\x97\x94\xe4\xaa\x90K\x82\xc8\xa3\xe5\x12\
+\x88\x98\x86XB\xfe\x0d\x89%0\x91K\xb1\x04*\xef\
+\x90X\x02\xe9\x16\x10K\x8ah\xd6+\x96$\xd5&\x17\
+K\x92\xcb\xa3\xc4\x12k\xf8\xbe\x87#Mvp\x1c\xf0\
+M\xd8\xbc\x09\x9b\xb0\xb0Q\x5c`\x16\xc43\x08\x9b\xa0\
+\xdb\xca)\xd8g\xbc<\xbcS|\x8ae\x82\x01 \xab\
+\xac\x0b\xab)M4\x97}f\x15lo%\xb5\x18\xb8\
+\xb4\xb4\xb0\xd8\x99c)\xea\xde\xde2\xc1\xbd\xb2\xf2!\
+\x97]\xd8\x06\x0c\x9f\x12\xb0\xae\xed\xc2{#`Yn\
+\xdf\x82\xd5\xc7\xd1\xae\xca\x0b\xbc\xbe\x8b\x09\x19\xa9\x9d\xf1\
+\x0c\xc6\x9b\xb5\x1e@\xdcnQ\xda\xea\xa5\xa9.\x0dJ\
+.\x8eiM\x8b\x95\x08\xc1\x98TuQ\xf9\x90\x1b\xea\
+`\xe0Y+\xdcX\x02_\xb1\xbb\xea\x5cP\xfa\x0d\x5c\
+I\xde\xbd\xcdE|^\xe8\x16#@\xce\x00\x87\xd4e\
+e\x8b\xdc\x5cwmh\xe4\x00yQ\xeb&\xd0\x80w\
+%a!f\xfbm+j\xa1\xa9\x11\xfbm+60\
+\x96\xf2&\xd6\xde\xc4ZX\xaca\x0c\x97\x11\xdb\xf8\x92\
+\x9ds\x1aQV\xd5\x01\x04\xf0\xc2\x88.\xc4Q\x19?\
+\x00\xebM0U\x17\x15\x7fsY\xe4\x1a\xb8\xe8\x01u\
+\x01\xbb\xb2\xb2\x0d\xec\xf5\x8dER\x15\xb6\x14\xb4\x82f\
+^Y\xdd{1\x1f!s\x1f\x8fJKM]\x1fw\
+\x9b\xe4\xe2\x88\xe5\xec\xef\x04\x12\xac\x90\xe9<v\xa0r\
+\x81\xc4\xa0GpX\x8b\x82\xfcO.\x8c\x10V)'\
+\x8c\x00\x88SW\x99\x9bm\x1e\xb4,\x85\x11\x80+[\
+\x04\x0e\xca\xe5@KC$vR\x17V\x8dry\x84\
+\xcd\x8c\x88rPkFE\xdfQ\xb3\xc1^i$\x8f\
+{yg{_\xde\x05\x83PZ\xbc\xf9uo2i\
+\x80L\xe2L\x18\xab\x1a\x99\x1bO\x95IO\x88\xd1\x83\
+\x19\x06\xfcl\x1a\xaf\xc8\xdf\x88\xf6\x8dhC\xe2\xb1e\
+\x99q\xdb{* \x18\xf5b\x22\x18\xa2\xe7\xb6?D\
+\xaf\xbd\x18=\xb1\xc08\x85\x15k\x8bx\xb6\x11\x92P\
+]\x17\x15\x7fs\x15\xeb\x1a\xf0\xa8\x00cUe\x1b\xd8\
+\xeb\x1b\x8b*\x0b\xd9\x05\xa3\xa9WV\xf7\x9e\xcf\x87\x83\
+\xfb\xe2\xf4\x9e\xa1\x5c\xeb\xba>\xee6\xc9U,\xc9c\
+\x17N\xc5j\xed\x8e\xe0c\xf7\xc5b\xa4\x95\xda\xc8\xb2\
+ \xff\x93\xabX\x84\xa5y`^\xe2k\x04\x8e\xf9_\
+K{\xbf\x00\x16\x95\xb9\xaf\xdd\xb7$\xb8:Q-\x06\
+\xfe*)\xfc\xc2\xaaM\xae`\xa1\x95\xb4*r\xa0\xf8\
+u\x9bE\xd7Q\xa3\xc1\xa0\xe8\xbc\xe4\x92\x19U\x9e\xd5\
+\xad>\x02E2%-\x87\x8dH\x84\xb2Bks\xe8\
+]z}<n5\xcdP\xc6\x81\xe4\x9al6\x9bz\
+\x0a\xf5{Z]\xbf\xbcut$q\xde\xd2\xc2\xbeP\
+\x86\x5c\x05\x93p\x84\xc4A\xf0I|w\x81\xe9\xfe\xf1\
+\xdb\xc9\xc1\xe8\xd0\x98\xed_\x82GH\xf1\xd5\xa5\xa4R\
+\xe5\x85V\xa2\x9fJQ^\x19\xcd\xc0\xb1D\x97\x87q\
+;R\x89\xa0Z\x08\x8d\xf6\x9b\x00~\x80Q,\xb8b\
+\xf0\x181\x09\xe4\x80\xa77\xa0\x04\x89\x13\xfc4\xfc\xca\
+^\x18\x0a\xdf\xff\xc38`\x12\xe2\xa1eK\x0cb\x99\
+&\x86q\xad8\x96)F\x8c\xc6;\xd2\xb0\x19\xe0\xfe\
+q\xe0e\x0d\xcf\xb0\xe30]&\xf0\xdb\x09\xd0\xa8S\
+`zJ|\xbd\x0f\xf2\x89\x80\x01\xa7\x82k\xf5^\xa1\
+\xf7\x9b;\xf8\xc5\x0a\x83<-\xef\x9c\xf8r\x99M\xb6\
+\xabu<\xb9_\x7fI\xb7\xf7\xeb\x0cO\xb3T{y\
+\xf08D\x11\x08\x90\xee\x90\x83\xb5\x96\xa0\xbb\xec\x0e\xe8\
+hMX\xeb\xc0\x83\xbb1N9\x80TI\xdd\xbdC\
+<\xde)\x9eC\xc7xd\xe0\x1cO\xe8 O\x05\x1f\
+U\x1d\x97\x95-X\xaf\xe3\xa2\xa6\xea\xb69\x85=\xe7\
+\x19Zg\x96\xfaN;5N2t\xb3\xdb7N2\
+tS\xe2\xd7\x02\x97\x926]xN9\x13@\x96\xb4\
+\xe7\x85\x07\xa7\xc3\x0e\x84\xf5\x1dp\x082x\xf7x\xda\
+)\xb3c\xc3B\x0656\x18\x19\x8a\xc1\xa1\xf8\xef\xdb\
+\xba\xc0\x96\xbfB\x0a\x0f\x9e\xbf\xc5oQ\x91\xa0\x86\x8d\
+\xc5\x10<\x88\x7f\xa6\xaa\x1c\xcf\x85\xeco\x9c\xe7\xe5\xb6\
+\xfa\xfe\xe3\x0e!\x80'JE\xfdm\xa4\x8d\x93k\xb8\
+98#\xcf\xdf\xdb\x15W8\xbc4\x9d\xe5y\xb2\xfc\
+\xa4\x19ltUS\x1cA\xe3x/\x13\x0c\xc4\xd6\x97\
+\xf7\xc2@\x9c\x8a\xce\x81\xa0zj\x86\xba_N\xca\x9f\
+\x9cX\xbf\x9b\x11\xf7\xcd\x1e=\xb4Y\x7f\xf3\x8b\xb7\x1a\
+\x0f\x95 y\x17x\xabg\xe4\xddo\xecbF1#\
+\x019\xc7\x0f\xdfY\xa6\xf5\x0e\xef4\xce\xe5Y\x0f)\
+%\x1e\x8b\x83\xb3^\xcd\x0e\x8f\xdf\xb5\xb0\xfe\xe8\xdf\xbb\
+\x09\xae\xf71x3\x07\xba\xd2x\x97\xc9\xf8\xe9\xee\xf7\
+\x0f\xbdw\xb6\xde\xdaz\xb6\xb0\xc0!+QH\x8f\xc6\
+\xe1\x9e]k\x12{\xbd\xec\xce\x0c\x94\x90\xd4\x82kV\
+\x0c\xccg23\xd3\xe6\xc0\x04\xac\x02\x90^J\x05&\
+\xe0Qj)\xdd\xf6Puu\xa1\x05u0`\xb7\xc4\
+y\x87c\x02;\xe7- \xb0k\x9d\x1e\xca\xa1\x9c\xb4\
+\xa05\xc7\x95'\xaf]\xb6\xa2\xee\x02\xc4>\x19\xd0\xc4\
+Q\xc0\xaa\xc1\x0b\x8a\xbd\xca\xa0\xb3\x8c=cX\xd37\
+\x06\x1d\xa0pj\xba\xab\x96X.[$\x86\x83\x91\xc9\
+[Xj\xcb\xa5\xe37\xa4\x09\xee\xb8\xb1!\x16\xf7\x8d\
+TL\xccQ\x84\x86\xff\xbaK\xd0O\xd8\x92A\xd6C\
+\xc0\xa7\x18!\x07\xe5\xfe\xc4\xfb\xeer\x0f5x\xc2|\
+\xe5Q\xdb+\x0e`\xb1\xc1\x04l\xef\xdex\xdb\x17\xda\
+\xda\xb84\x17\xcc\xc1\xddm\x0ctpk\xabkS'\
+\xa1j\x88\xe9\xb5g\xa7\xe2\xa3\xf76>\xc3\xe6\x12{\
+\xdc\xe6\xdaa\x9b\x1b\xe0\xdd\xee\xfez{\x18\xdc\xe2\xfc\
+&js\x8b\xdb2v\x9f\xf4\xf6E*\xab\xf5_\xb9\
+\x12A*\xb5\xb0O\xe2\xb1\x135\xcfy\xb6w \xe7\
+J\x22\xf6o.\x19\xf4\xf2\xd0C\x89\x0a o\x80T\
+vN9\xf3\xa4\xb2D\x7f\xd6\x04\x18\xf7\x04\x0a%f\
+\xc8}\x8az\x11\x92\x9c&~\xca9W\x8b(V\xb5\
+G\xb5\xd4\xb5{z8Q\xb7\xc0\x02\xd8\xe9\xecL\xb4\
+>N\xdd?M\xb2\x94V\xc1\xc9\xd6\x19\x90\xa8\xe8g\
+\xd8\x1e\xeb,\xc6o\x8cT\xc6\x17(\xb5\xc4\xe8\x11(\
+\xc2\xef\xa4I\xbb\x076-h\xa0\xc1\x1a\xd4Sx\xf4\
+Tk\xa0W\xa4<\xb6\xc9q\xd7v\x09OZ*%\
+\xfdR\xb3w\xa9\x94\x0c\x89\xb0\x1d\x10\x86\x03\x85\xe70\
+\x02>0\xdd!w\x17=\xd4\x84T\xcf\x10\x9b\xb6\xa3\
+\x16k2=\x8by\xce\x8f1\xcf\xc1\x9a\xd7\x03\xd6\xd1\
+\xf6`v\x01\x8b,\xe0\x11\xf5;\x85\x87\x9c\xa9\xce\x08\
+\x87h\xb8\xe5Xxk\xb4O\xa0\x0b\xce\x8f#\xe3\xde\
+\x95v&\xa0\x8d\x0b^\x1c\xebp\xd7k\xab\xbe\xf1\xcc\
+\xd74\x9e\xe4l \xcd\x13\x0f\x1d\x05X\x8aW\x9c\xf3\
+G\xbc\x1f\xff\xf9\xdd\xff\x03\x0b\xb0\x0a\x0c\x99\x9b\x00\x00\
+\
+"
+
+qt_resource_name = b"\
+\x00\x05\
+\x00o\xa6S\
+\x00i\
+\x00c\x00o\x00n\x00s\
+\x00\x06\
+\x07\x03}\xc3\
+\x00i\
+\x00m\x00a\x00g\x00e\x00s\
+\x00\x16\
+\x02\x1b\xe1\x0a\
+\x00g\
+\x00o\x00-\x00n\x00e\x00x\x00t\x00-\x00v\x00i\x00e\x00w\x00-\x00p\x00a\x00g\x00e\
+\x00.\x00s\x00v\x00g\x00z\
+\x00\x11\
+\x04\xf3\xa4*\
+\x00g\
+\x00o\x00-\x00n\x00e\x00x\x00t\x00-\x00v\x00i\x00e\x00w\x00.\x00s\x00v\x00g\x00z\
+\
+\x00\x15\
+\x01\x09v*\
+\x00g\
+\x00o\x00-\x00p\x00r\x00e\x00v\x00i\x00o\x00u\x00s\x00-\x00v\x00i\x00e\x00w\x00.\
+\x00s\x00v\x00g\x00z\
+\x00\x0d\
+\x0e\xb9\xa6*\
+\x00z\
+\x00o\x00o\x00m\x00-\x00o\x00u\x00t\x00.\x00s\x00v\x00g\x00z\
+\x00\x12\
+\x0al\x90\xca\
+\x00d\
+\x00o\x00c\x00u\x00m\x00e\x00n\x00t\x00-\x00o\x00p\x00e\x00n\x00.\x00s\x00v\x00g\
+\x00z\
+\x00\x1a\
+\x01d\xbbJ\
+\x00g\
+\x00o\x00-\x00p\x00r\x00e\x00v\x00i\x00o\x00u\x00s\x00-\x00v\x00i\x00e\x00w\x00-\
+\x00p\x00a\x00g\x00e\x00.\x00s\x00v\x00g\x00z\
+\x00\x0c\
+\x009l\x8a\
+\x00z\
+\x00o\x00o\x00m\x00-\x00i\x00n\x00.\x00s\x00v\x00g\x00z\
+"
+
+qt_resource_struct = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x10\x00\x02\x00\x00\x00\x07\x00\x00\x00\x03\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x010\x00\x00\x00\x00\x00\x01\x00\x00\xba\xe2\
+\x00\x00\x01\x81\x8a\xd9\xf0\x94\
+\x00\x00\x00|\x00\x00\x00\x00\x00\x01\x00\x00J'\
+\x00\x00\x01\x81\x8a\xd9\xf0\x94\
+\x00\x00\x00\xf6\x00\x00\x00\x00\x00\x01\x00\x00\x89\xa4\
+\x00\x00\x01\x81\x8a\xd9\xf0\x94\
+\x00\x00\x00\x22\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x01\x81\x8a\xd9\xf0\x94\
+\x00\x00\x00T\x00\x00\x00\x00\x00\x01\x00\x001K\
+\x00\x00\x01\x81\x8a\xd9\xf0\x94\
+\x00\x00\x00\xcc\x00\x00\x00\x00\x00\x01\x00\x00x\xec\
+\x00\x00\x01\x81\x8a\xd9\xf0\x94\
+\x00\x00\x00\xac\x00\x00\x00\x00\x00\x01\x00\x00c\xbc\
+\x00\x00\x01\x81\x8a\xd9\xf0\x94\
+"
+
+def qInitResources():
+    QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+def qCleanupResources():
+    QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+qInitResources()
diff --git a/examples/pdfwidgets/pdfviewer/resources_rc.py b/examples/pdfwidgets/pdfviewer/resources_rc.py
deleted file mode 100644 (file)
index 7e386e9..0000000
+++ /dev/null
@@ -1,3468 +0,0 @@
-# Resource object code (Python 3)
-# Created by: object code
-# Created by: The Resource Compiler for Qt version 6.4.0
-# WARNING! All changes made in this file will be lost!
-
-from PySide6 import QtCore
-
-qt_resource_data = b"\
-\x00\x001G\
-\x1f\
-\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xec}\xebs\x1b\xc7\xb1\
-\xef\xe7\xe4\xaf\xe0U\xbeDU\xc0\xb0\xdf\x0f%\xce\xa9\
-\xc4\x8eS\xa9r\xea\xa4n\x1e\xf7\xdcO.\x88\x04%\
-\x1e\xd3\xa4\x0eI\xf9\x91\xbf\xfe\xee\x02$g!h\xb1\
-\x00\x16P$_s\x5c\xf2b\xb6\xb7{\xfa7==\
-=\xb33\xb3\xbf\xfd\x8f\x1f\xbe\xbd:\xf9n~{w\
-ys\xfd\xd93,\xf0\xecd~}vs~y\xfd\
-\xea\xb3g\xff\xf8\xfb\x97\xd3xvrw?\xbb>\x9f\
-]\xdd\x5c\xcf?{v}\xf3\xec?~\xf7\xcb\xdf\xfe\
-\xaf\xe9\xf4\xe4O\xf3\xeb\xf9\xed\xec\xfe\xe6\xf6\xc5\xc9\xef\
-\xcfo^\xceO\xfe|u\xf5\xf6\xee~\x91u\x82T\
-\xa0\xc0\xe4\xe4o\xff\xfc\xd3\xc9\x1f\x7fxss{\x7f\
-\xf2\xd7\xab\xb7\xaf\xa6\x7f\xbe>)\x8b\xcc\x7f.e\xbe\
-8\xb1\x02p\xf2\x87\xb7\x97W\xe7'\x8a\x22\xf1\xfc\xe4\
-d:mD\xdc}\xf7\xea\x97'''M\xf9\xae\xef\
-^\x5c\xdf}\xf6\xec\xf5\xfd\xfd\x9b\x17\xa7\xa7\xd7we\
-\xd6\x8a+g7\xdf\x9e\xfem\xf6\xdd\xfc\xcb\x9b\xdb\xff\
-3\x7fy\x8a\x05N\x9f\xd5'f\xef\x7f`Q\xd2F\
-\xfe?/\xe7\xdf\xcfo\xff\xf8\xc3\xfd\xfc\xba-\xc6\xdd\
-)\xaf>~\xb9\xe1\xf1\x8e\x9e\xa7\x08\xab\xcf\x9d\x9f=\
-=\xf8\xe6\xed\xedU\xb9\xb9}uz~v:\xbf\x9a\
-\x7f;\xbf\xbe\xbfkJ\x89]\xf2\xb3J~v;\x9f\
-\xdd_~7o\xc4|\xdb\x14\xa8}\xb2\x91\xfd\xab\x0e\
-\xf1\xed\xf9\xc5\x13\xf5\xf7\xdf\x7f_\xbe\xe7\x05\x11f\xe6\
-)\xd0)\xd1\xb4\xa1\x98\xde\xfdx}?\xfba\xba\xfa\
-h\x03\xe6\xfb\x1e%\x008m\xeeU\xca\xed\xa8^\xfc\
-puy\xfdMoa\x16w\xbb\xd2\x1b{zss\
-^1}\xcc(w7oo\xcf\xe6\x17\xcd\x93\xf3r\
-=\xbf?\xfd\xe2\xef_<\xdd\x9cB9\xbf?\xef\xb0\
-i\x98\xde\x9d\xcd\xde\xccW\xe4>f.\xf1\x9a};\
-\xbf{3;\x9b\xdf\x9d>\xe6\xb7\xcfw\x0d\x1c\x17\x19\
-\x97\xe7\x9f=\xfbj\xf6\xe3\xfc\xf6\xeb\xe5\xef\xef/\xcf\
-\xef_7\xb7)\x16?_\xcf/_\xbd\xbe\xaf\xbf\xbf\
-k\xac\xe5\x0f7?|\xf6\x0cN\xe0\x04)N\x1eo\
-\xdc4\x9c/\xaen\xbe\xff\xec\xd9w\x97w\x97/\xaf\
-\x96\xe2\xe6\xd7\xb3\xe6r\xfarv\xf6\xcd\xab\xdb\x9b\xb7\
-\xd7\x8d\xb0\xeb\xf9\xf7'\x9d\x87\x1f\xb5z\xd1\x96\xb6Q\
-\xe8\xcd\xed\xfcn~\xfb\xdd\xf2\xf1G\x00^<\x15\x1b\
-\x0a\xd3\xe2\xd6\xa3V\xdd[b\xabO\x9d\xdf\x9c58\
-4L_\xddL\xaf\xe7?\xdcO\xdf\xcc\x1at\x9b\xfa\
-\xfb\xd7\x1a\xdd\xcb\xd9]Cw\xfa\x8f\xbb\x86\xdb\xe9\xf9\
-\xec\xbb\xcb\xf3\xd3/\xe6w\xdf\xdc\xdf\xbc9\xbdk\xda\
-\xfc\xcb\x9b\x1fV\xa5\xde\xbc\xbd\x7f\xf3\xf6\xfe\xeby\xdb\
-l\x96\xe2\x1b\xd4k\x15,o/D=e\xae2\x98\
-/\x5c\xc1\xf4\xe2\xf2j\xbe,\xe3\xe9\xeb\x9bo\xe7\xa7\
-o.\xaf\x1b\xc8oo\x9a\x8b\xb3\xbb\xd3\x9b\x1f~|\
-5\xbf>m\x9e\xb8jq<\x9d\x9d\xdd/\x9a\xe8\x8a\
->o\xae_\xbd\x97\xf5\x0f\xe7o\x1a;3/\xfa\xde\
-\xdb?\xd6\xdb\xbf\xfb\xed\xf9\xfc\xe2\xee\xd1\x1a\xdak\x84\
-6\xf7\xe9\x917\x0d*o\xe6gm\xa3\x5c\x01\xee\xfe\
-\xc7\xd6\x06W\xc9\xf8\xfc\x9d\xfay\xf3uc.S\x85\
-\x93\xc6\xc3A\xfb/\xae\x11\xfc\xd8\xd4^{\x03\x16\xf7\
-a\xed\xfe\xbf>{\xe6\xb0\xce`U\xec\xf4\xe6\xf6\xf2\
-\xd5eS\x13\xbc \x92J\xbaP\xab\xa3\x03!=;\
-9\xfd\xe9\xea\x87\xa6\x0b\xfd\xbe\x9d\xdd~3\xbf]\xe1\
-uw\x7fs\xf6MK\xfe\xfb\xdb\xdb\x9b\xef\xf1/\xf3\
-\xeb\xa5:\x0d\xef\xf9u\xd3\xcego\xefo\x16\x19\xb7\
-\xf3\x8b\xff\xdb\xb6)x\xfc\xf5_\xf5\xd7{\x9e\xbf\xbb\
-\xff\xf1\xaa\x81\xea\xd1\x0b\xbcxp\x02\xbfi\xac\xe8\xcd\
-\xec\xfeuK\xb2|\xae\xfd\xc5\xac\xfel\x99\xd5\xe4\xfc\
-\xe5\xa4\xed\x1f\xa1\xc0\xc9W'\xda\x5cMuq9E\
-*\xda\xc9^\xe4>\x91\xfe\xeb\xa4eP\x057\xed\xe8\
-jz\xfb\xf6\xaa1\xef\xef\xe6\xd77\xe7\xe7\xbfi\xfa\
-\xa5\x9bo\xe6/~\x05\x8b\xbf\x87\x9f\xd3\x85{{\x81\
-\x05\xde\xdc\xfff\x09\xcf\xb4\xe9\xd4o\xef_\x5c7\x9d\
-\xfao\x1ex6=\xda\xf5]\xe3\x8a\xbf\xfd\xecY\xdb\
-\xf4\xe6\xbf\x86\x22\xcfOno\xeeg\xf7\xf3_c\xc0\
-\xf3%\xc5\xd5\xe2'L\xe0\xf9\x02\xed\xd3%\xbf\xad`\
-_\xc8\x1c\x01|\xe5\xd0\x0b}\x1f\xf2\xf21\x22\xbf\x01\
-\xf8\xd1`\xffm4\xd8\x7f\xdb\x17l\x83O\x0bl\xea\
-\x82m{`\xfd\xd5H\x7f\xf2\xd5\xbe\xfe\x04?1\x7f\
-\x12\xbd\xfe\x84\x8a\xee\x03\xfch#\xffj_#\x97\xf8\
-\xb4\x8c<\x06\xe0>h\x5c\xb0\xe8\xd4e\xdf\xa0\x00)\
-\xea\xf3\x1bc\x82\x05\x8dP\xb1\xf6\xcf{\x03\x83\xf0\x85\
-\xa6\xcd\xa8d>\xbb\xfd\xd3\xed\xec\xbc5\x95\x15\xc6g\
-7WW\x0dqc>W\xdf\xcf~\xbc{\xe2\xb2\xfa\
-\x88!rc\x0e\x8d\x11\xbeY\xa9\xba6c\xda\xb0\xb8\
-\xb9\xad\x95\xd5f\xdd4\xc1\xfd\xe5\xfd\x8f/\xf0\xb1I\
-\xdc\x5c\x5c\xdc\xcd\x1b)\xf0\xac\x9aSKi\x88m\xec\
-\xb2\x07kx\x975\xae\xb3\xf6e=\xaf\xea\xf2\xbb\xdf\
-\xb6\x17\xb3\xab\xad\xe1X\x0c\xea^\xbc\xbe\x9d7\x83\xd0\
-_\xad\xf2b\x02\x7f\x82l\x95-Q\xe8\xe2\xd6\xab\x87\
-\x8c\x7f\x5c_\xde7\xa3\xcc\xb7\xcd\x90\xe3o\xed\xd8\xe7\
-?\xaf\x9b\xd1\xc7\x0a\xc5\xdf\xab\xf1~;\xbb\xbf\xbd\xfc\
-\xe1\xd7X@\x88T&\xd0\xa6\x82d\x802!,\x9a\
-\xed\xc54\xa8\x18z\xe2\xf3\x05\x9f\xb3\xc6\x00%\x0b \
-\xa6\xe32\xa71:*\xe6\xc2\xe0\xb1\xc8\xb9X\xa3\xb9\
-X\xa3\xb9m\x87\x8bNb\x98\xdcc?\xeb&B\xc4\
-4d\x22/%\x85f;\x9a\x08\x11\xcb\xb0\x89\xcc\xe5\
-\xfc\xec,\xdfa=`!Dl\xef\xb7\x90\xfa{\x84\
-\x85TX\xfa\x10\x0b\x1em!P<\x125\x17\x16\xf2\
-\xf4\x83\xb0\x80\x85\xca\x84\x8b\xa4\x13\xc5|J\xcf\x97E\
-\xc5E\xfd\xa32,\x85\xff\xd8d\xb8\x16F`\x8c%\
-\x09}\xf6,\xa8H\x88\x09-i\xa8C\xb3\xb5E0\
-\xb1>\xdb\x88]\xad\xd3Z)L\xeck\x16\xd1[\xed\
-\x17\x8b\xbf5\x8b:9\xeda\x9dk&\xb1\x13k\xf8\
-\xcd\xf1\xec\xa5\x82\xd6o/x\x00\x8f\x82H\xc29\xc1\
-\x02\xac\xc26\x99\xb6Wh\xc6\x93\xf6\x9e)\xf8\xc4\xb4\
-\xa8\x83\xf2d*YP\x08\xa5c<Q$C\x8d\x9e\
-\xac\x07J *H\xda\x93\xf9H\x14gr\xe2'\xf3\
-\xa1\xc2\xa6N\x96;\x98\x0fx\xb5\x90\x81:\xda\xc5\xa1\
-0A\x0e;\x14\xd26\xed\xd8\xe70!\xfe[\xfb\x1c\
-\xcf\x03X\x88bz\xedsBRh\x82R\x02\x12\x1a\
-\x93p/\x88\xea\x1fC\x9f\xc3Dz$\x13!\x1f6\
-\x91\xd9\xbcM\x03\xacq\x9du\x1e\xdfDH\xfbM\xc4\
-\x8f\xe1D\xa0p\x84yL\xa0\x08\x81\x89L\x0c\x0aB\
-\xd0d*\x5c\x88Am\xd5` #\xe4\xc9`\xa2H\
-*#Q5\x18/\xec\x10\x11O\x06c\xc5\x1d\xd0\xd2\
-\x1f\x0d\x86K\xba\x82\x80no0L\xfa\xfe^\x87\xe9\
-h\xbd\x0e\xd3\x11{\x9da\x8d\x81\xf7i\x22P,X\
-\x94\xc9\x06\xdb\x0a/*`\x0f\x19\xc3\xee\x94\xe1\xf8!\
-<\x03\xf7\xb7\x95C\x04h\x99\x99m\xb0\xee%\x04M\
-l>\xe5\x89\x163\x03\xcf\xf9T&T@\x82\xa1\xc9\
-\xa7\xb63&!bi\x89\xbch \xab\xd7\x86\xc3R\
-\xcc\xdd8\x9f\x1a\x8e\x171\x22\xb7e\xce\xc5\x1a\xcd\xc5\
-\x1a\xcd\xed\xa2mi*f\x0b\xeeA\x83\x17\xd0\xe8\x0d\
-^\x1c\x0f\x80e\xa8)P\x1b\xe8f\xea\xd2\xefx\x9a\
-Q\x9b\x15\x9a\xc62A\xd4\xa2H<\x99\x12\x96d\xf1\
-\xac\xc1\x0bba2\x0ey\x0a^\xd4\x0b\x07g\xe6S\
-\xec\x82R$Y\x19\x974Tiv\x88]@\xe3\xfd\
-~\x06\x0c\xb6\xf739s[\x1fRo1\x18\xe2\xd9\
-\xf9\xf0P\xbc@R\x12\xb0=[+\xa3\xf5\xf92p\
-Xc\xa3 \x8c\xbe\xd1\xa7\x9d\x9d\xd3\xd9\xb6\xee\x12,\
-\xd6D$\xaa#\x87>\x1bPy{\x19\xb4\xbdK~\
-\x99\xd1\xc3\xfa\xa8~\x094z\xfd\x92\x8d\x0f\xf3\xb4\x90\
-9\x0b\xb6^G\x0b(\x1a\xca\x83\x07\x02uOY\x0e\
-\x07\x88\x9b\x8b\xe0\xe2\xae8\x99\x9a\x15\xe5\xd0\xe8x$\
-+\xe6j\x12O\x1e)\xb5\xb8%y\xf5Hh\x85\xd0\
-Y\xa5v\xe5RP\x90\x02;\x1e\xc9\xc5\x04v\x98o\
-\xd0|\x7f\x13#\x83\x1d\x9aX\x0d\xf3\x87\x9b\xd8\xf0s\
-\xebm\xe3\xd9Z\xe1\xfa\xda\x16\x19\xac\x1b\xbe\xeb\xb8\xa2\
-w\xb9\xef`\xf2\x00\x00\x1f\xde\xe4Is\x83\xc9\x1f\x22\
-lU\x09\xe5\x09\x16\xb1D\x94E\x0f\x01\x8a\x16\x13\xa2\
-b\xa1\x19\x13$\xa7\x92\xd2\x0e\x8b)\xb1\x08P\xb5u\
-\xd4\xe2\xe4\xe0\xfed\xeb\x1a\x05\x22-\xbc\xda\xfa\x0a\xcd\
-\xc5\x1a\xcd\xedb\xe0\x83\xc2i\xba\xc3\xdc\x9a\xfa\x91\xe6\
-\xd64\x8f5\xb7fxt{!\xf5~{9\xc4\xec\
-+1\x1a\xda\x04\x0b%\x0aac\x14X\x1c\x16YX\
-\xd0\xa3u\x8e\x82X\xc2\xa5\xb9\xc7\xa4E\xb5c0B\
-\xc5\xd0\x95\xeb\xc0\x18\x09\x8a\x09>\x8ej\xd6h.\xba\
-4u\x9c#`\x11\xbb\xcc\xbc%\x0e\xd8\xcb\xcb\xabf\
-\x8d\xceZ\x95\x0e\x0c\x8a\x17C\xf3\x9d\xf9\xc2\xe0\x888\
-u\xdb\x01N\x1b\x8e\xc1S\xa8F\xd1\x8d\xe3\xf4)\xcc\
-\xa3\xd8\xb2\xee\xd7\xa1\xc30k\xfa\x95_\xfe\xe2\x17\xbf\
-x\xd0\xb3\x16\x14\xc3\xda\xf0\xa7w\x80sv\xf6\xdey\
-\x86\x0ah\xa3e?g\xea\xe1\xfc\xfd\xeb\xcb\xfb\xf9\xfa\
-\xc0\xa9\x0b\xe8\x03\xdf\x8f\x03@M\xf3>\x005-\x07\
-\xd4\xdc\x0b>M\xc7#\xc3W\xdb\xda\x7f\xfd\xe5\xab?\
-\x7f\xf15}\xbd\x1dD\x15\xcf\x8as\x17\xffZ)U\
-\xb7n\xe9z\x0d\xee\xcb/\xff\xf8{\x80g+8\xd0\
-\x1aDU\xc9^6\x9f\x7f\xfe.\x1b\x19@d?\xe7\
-\xbd\xc4-\xbf\xee\x1b!r\xe2\x0e\x90\xa6\x14\x16\xae\xb8\
-\x22Pa\x11\xaf\xaf0\xac(\xab=\x01\x9cR\x94\x1f\
-F6\xe3\xd5@\xd8\xa0\x07\xef\xa2\x87vT\xe0\x95\xd2\
-\x87\xe9J\xe9\xc3\xf4P\xa5\xc7\x0d\xa5\xd7\x03\x94\xde\x0b\
-%\xd7\xc2k\xfb\xf3Pe\xa7\x0de\xf7]\xcan\x9d\
-\xb2K-{\x14\x00\xa0Zx[\xfe>9\xad\xb1\xcb\
-\xfe\xa5\xf7\xaf\xfb\x22\x16\xd9&b\xa9\xb1(P\x0d*\
-\x90\x0a\x83<\x05\x98\xc8YTC\x0fT\xe4\xd8Pd\
-?p\x91s\xe9y~\xdb\xc4a\xcdJ\xe4\xeb\xff|\
-\xf9\xdfM\x01\x174\xf3\xffy{y;?\xaf\x0b\xd7\
-w_\xa7\xfe\xe8L\x1b\xf9\xb0\xb2\xf8yu\xe9\xf3\x93\
-\xb6+\x85X\xf6i\xbf\xbd|\xf1\xe6\xd5\xc5\xff\x9e_\
-\xaca\xb5(\xc2\xd7\x97U\xf2\xd7\x0d\xe1\xf2\x99\xd3\xc7\
-\x87Z\xcdNW\xb869\xbf<\xa6SEb\x87O\
-\xdb\xabVE\xe8St\xab\xb5\xf8\xf2\xe9\xf9\xd5Zx\
-;\xaec\x1d_\xfc\x8d\xa5\x8f\x03\xc7j\x07\x9e7'\
-\x86\xec+\xbd`\xec\xd2\x80\xa7.%\x08\x1c\xbcS\x07\
-P\x82\xd8\xeb\xea\x8e)FA\xc2\xac\x0d\xa1\x12}X\
-\xd5\xf2\xd3T\xad\x8et\xfaGA\xce\xbb\x18\x9d\x17\xc7\
-t\xa9-\xc7K\x04\xd6\xe6\xb3F\xd2\xe40\x14\x11\xc4\
-\xd0\xbey\x8c\xce\xba\xc7\x22\x0e\x826\x9f\xb6\xcb\x1f?\
-`\x1dk\xba\x7f\xd0:\xae1\xcf\xe1\xebx\x95/j\
-\x86=E7d%U\xba1\x0ec\x01Q\xd0e)\
-/\xd6h.\xd6h\x9a@(JZ\xa0\xf2\xf0\xb2/\
-\x95\xf4\x98L\xa9\xa4&\xc7b\x1e\x1f&P\x12\xd4\x9d\
-&^L\x81\x5c'\x08%<\xc0\x9f\x0f\xd7\xc2\xd1=\
-q\x98\xfa\x11<q\x1bc\xadJ\xea\x95/\xf9\x11\x8e\
-\xda\xc3\x14G\x0e\xdc+'\xee\x19\xbb\xb7yM\xf8y\
-@\xf7\x17f\xd1_\xd3.\xbb4{\xce\xa2\x8cT\xa3\
-\x9e\xda\xdc\xeb\xcd\xfaB\x16\x0b\x86\xeb\xf1\xed\xd5E\x8e\
-`\xaf\x1f\xac\x12\x5c\xec\xd8\x95p\xf4A\xa6i\xc8!\
-\x16ax8\xf1\xe3\xa2\xb6\x0cl\x12M\xb2\xb0\xa1\x03\
-\xe1\x04\x0b\x1a7I\x9e\xef6^=\xf6\xb4\x80i\xf8\
-\xfe\xea\xd7\x00 \x9an\x7f\xe4\xe4\xc1xC\xed\xd11\
-\x95\xa0\xbeP\x86\x02\x08\xc8Y\xfbQ)\xae\x80R_\
-(\xaf\xd2\x5c\xac\xd14j\x10\x14\x0f$\x1dz\xc5\xb3\
-0\x08,\x94h\x08\xadyLQ\x8bzrl\xd1a\
-\x1e}N\x88>\xcd\xca\x1f\x9e9\xa2\xc8\x8f\xbbQ\x1f\
-w\xaa\x9b~\x22S\xdd\xf4IOu\xd3'<\xd5M\
-G\x9c\xea>~\xebw:Z\xeb\x9fb\x14\xe3\xa0\xb4\
-\xc9\xd4J\xb0\xb5\xe9#\xeb\xd4\x89\x5c\x0f\xe1\xd7\xa7\x98\
-%\xdb\xbf\x98Lc\x0f\x0f\xdf\xec\xbc\xbc\x9f\xdfn\xb5\
-\x1fpI\xca$\xf8\xacyn\xfe\xa7\xd9\xdb\xbb\xbb\xcb\
-\xd9\xf5\x1f\xae\xde\xb6\xcf\x0fqh\x070\xe7_\xcc\xbf\
-\xbb\x9c\xdd?\x1e\xb7\xc3)\x8a\xd2Y\x0a\xb0\xca\x94I\
-x\xb9(`)\xf9\xa8\xf5! v\x88\xfa\xa0\x22\xd0\
-\xfe\xe1|j\xbbv\xb9\x07\x1e\x18\x18\x22\xf7o\xe6\xcc\
-:f\xe1\x22\xe1Fu3\x98x\x81\x8c\xf0\xda\xbd`\
-1\xf5\xb4\xac\x1d\x0ceAb%\xdbkRa\x10G\
-\xe3\x92\x92\x16-\x88O2\xa7X\x04\xc4M\xa2\xfa\xaf\
-B\x1c\x86\x91O\x85\x9f\x22\x970\xc9\xa4G\x0d+\xd1\
-\xdeK\x1a\x982\x86\xb7\x5cDl\xde\xec\xb6\x8eC\x9d\
-\xbc\xf2\x92*Y;\x15\xe7\x22F\x16\x9d.\xc7K\xfb\
-\x1b\xa3\xea\x05\x85\xc5\x1c\x87\xd7L33?\xf9\xc9h\
-\xff\x12'\x98\xc5\xc5\xc3x\xc2X C\xd9\x9f\xef\x8d\
-\x10\x11\xf8 BL\xbc?BYB\x12\xac\x8e\xa9\xa1\
-3J-h\x0a\xd01j\x18\x02e\xc2\x85\x1f`\xa1\
-\xa2\x9a\xbc\xd8\xa9\x02\xc58\x83|2E\xcbB\x8c\x8e\
-\x13\xcbb\x0a\x969\x0a\x1d\x19F\x07e_tH\x8b\
-\x87\xa1U\xfb\xe1,d\x81\xd5~*Mg-<\x17\
-T'\x1e\xf6k\x88%\x17\x7f\x13\xd8\x1f\x05V\xe5\xe1\
-\x99\xe4\xcc\x8f\xc5F\xaa\x85@\xb5\x8cj-\x0b\xc3\xe0\
-@\xb4\x07k\xc1D\x1e\x85\x0e\x8e\xb0\x91\x8f\xcb\xc7$\
-\x1a\x89\xc6D\xa0X\xfb\xa7\x13\xa6\x02\x16\x064\x06!\
-\xc9c\xfa\x18\xa6\x0a\x8d\x14f`\xa2\xda\xafh\x09\x06\
-B\xb2\xda~\x80\x0a#\x92\x0c\xaf:v\x14\x0a[\x80\
-C\x8b\x0d\x94\xa2\xca\xea\x93)\xc9(<|\x0b\x8b\x81\
-\xbd\xbd\x8a/\x1b}\x85\x05I\x0a$j\x85%sA\
-\x13Z\xb7\x07Sq\x0ac\xd9\xab[\x9aLu\xd9\xea\
-\x96\xadj\x99k\xa30\xd2A\x9f#\x8c\xfbb\xa4\x92\
-\x05\x0cY:\x9e7\x8b\xbbXg\xc0\x85&\xc5,\xab\
-\xe5T\x9a\xcd\x18eq4\xd5\xc8\xf9\x94\x1e`B\x06\
-\xc4\xe4vh\xc3`h\xe9\x8d=aQ`\xe5q8\
-\x0d\xfaf\x17\xa2]q:t\xcfr\xa0\x1e\xaf\x17\x05\
-\x941=\xd4O\xdf\x07\x93\xb2\x8c\xf0\xc1?\xf1>\x9c\
-\x94\xc7\xf7\xe1\xbb\xece\xe6\xbe\xbd\xcc\xba\xfd\x06\xa83\
-?;?\xf7m7\xce\x89\xc6\xb8\xbd\xcc8\xfe\x04\x8d\
->8P\x8es\x16\x00\xa3\x1dm\x7f3\xc6\xf1\xe0\x80\
-c\xc1A\xc7\x83C\xf6\xdf\xe9\xeeB\xf4\xde\xf6\xe0B\
-\xb2}{x)M\xb2\xdd7\x04\xe6Y\x9e\xcdp\xe7\
-\x0d\x81\xca\x12\xc3\xcc\xcf\xce\x9bF\x8a;\x9e4\xe1B\
-\xb6?\x9c$\x8c\xef\x85\x93\x84\xf90G%\x8c\xb7\xcd\
-\x22\xa4\xe9\xe0\xf9l\xad\x8c\xba\x85\x0cl\xd3p\x95E\
-\x92\x07\xae\x8b\xf0\xbe\xbd\x96\xc2\xb9\xc6%\x800=6\
-\xb8\xcb\xf9\xacM\xdb\xee\xe7\x14\xc1\xed=\xf1\xf9E\x93\
-\xd6\xd0\x1ca\x1c\x9c9\xe4] -\xe6\xbbz\x17\x12\
-\xc0m\x0e^9kv[\xed\xd8\x1cH\x80\xc7;\xdb\
-\xe1\x18\xb9\xcf!\x8fx\x97;rD\xf0\x03n1.\
-\xa1.\xcd\xda\xf8\xe6\xd0+\x06\x85\xb1\x1f\xa7\x1c\xc6\xe9\
-\x90\xa3\xcb\xf5\xb1\xeb\xfa\xf8\xb6o\x0c\xdc\x1d'\x1f\x18\
-#f\x84^\x8c\x92\x861\x1a;/\xb1>\xcf\xb1>\
-\x19\xb2>cR\xa7Sv\xd8\xae\x1a\xb1\xcfAq\xb9\
-\xc3>\x7f\xc3\xb88\xa7\xad\x0f\x8a\xcb\x1d6\xcb\xcf\xe4\
-\x0c\xe6\xf2\x0e\xeb\xf7y\x9a\x9e\x93F\xd7\xcf\xedd!\
-\xdd\xe1L\xf0\xa1\xf3\xc5\x87\xcf\x22\x1d>\xe1|\xf88\
-\xd4\x83/*\xce\xec3\x7f\x07\x19m\xfe\xd3\x87\xa5?\
-\x13$\x99\xac\x98;\x14\xa0\xd0\xac\x13\x09P\x10\x03\xba\
-\x93<Q\xc0X\xc1\x1f\xad\xbd\xd2\xec\xf9^\xd5\x9d\x0e\
-\xf1^\x15\x8a\x02\x18\x93lx\xb1\xea.\x1f\xec\xc5*\
-\x19\xc8A\x160\x15h\xffh\x22\x1f\xd9:&\x03;\
-\xf6:&\x9d\xe8\xc7\xba\x8c\xc9 ~\x12\xcb\x98\x0c\xe1\
-\x13^\xc6dH\x9f\xec2&C\xf9\xd0\x1b\xcbZ\x0a\
-\xb3B$\xa2\xd5\xf6\x94\x0aa\x88U\xf34.\xc8\xa1\
-\xa8\xb5kH+b!6\xec\xb0\x90\xa3x\xb8\xc4d\
-\x0aK6\x9e#\xa6\xe7Ilx\x01\x82\xc1\xfe\xd3\xae\
-V\x84\x5c\xad\x86\xb9h\xc51\xc4k\xd0\x07\x85\x0d%\
-H\xadNM\xfb\x12\x8f\xf87\x00\x22\xc7\x04$t\x81\
-\x87\xe6\x13 \x92\x0b\xfbp\xaa\x16h\x0fz\xd4\xf1\x83\
-\x97\xb4\x96f;8t\x02\xa3\x10\xa0a\x04\x80\xf6E\
-\xc0\xb4\x88\x04\x22U\x93p.\x19\xe0X\x11 .\xae\
-aR[\x88gA'\x921z\xc1\xb0^\xa9\xff&\
-\xbd\x86k6}\x5c\xb5r\x8cV\xbf'\xeaiB\x03\
-\xb5z(\xa4\xd53\xab\xbc\x06\x13n5\xc6p\xdar\
-\xf5<rpR.V\xcfCQ\xf4P\xdf\x05\x83\xd5\
-\xb22\xb1\xf5u%\xf2\xf5x\xcd\x91\xb0\x88\x10r\x05\
- \xa2D\xa0\xf3G\x06\xc3\xa0\x8f33\xdb\xfb\xdd\xb5\
-\x17\xf2$\xae-\x81\xc8\x8au\x06>\xca\xc5CP\xb9\
-\xbep#.L\xfe\xd0z\xee\xde\xdc\xceg\xe7\x7f\x99\
-\xdf\xbf\xbeiK?\xbfh%o\x85\x15\x940\x041\
-n\x91\x8a\x82\x86\x1c\xcde\x116\x0c\xf3Q\xed\x87\x8e\
-\xdaSZq\x05\xeft\x0c\x1e%9\x99+l(\x85\
-\x5c#\xaa\xfbp)\xae\xfd\x90\x8d\xd0\x96\xf2\x88\xde\xc2\
-\xa0\x1e\xd8h\x85E\x14\xea^V\xa7\x02\x04\x81\xb5\xcd\
-\xac\xd2\x9cui\x86\xc6\xe2P4\xd0(t\x82\xc5\xcd\
-\xdd\xbc\x9d\xe0\xa4b\x19F\x92\xed\x0f(\x11\x1e\x19M\
-6k\x01\x0f\xb4\x89\x96\x14LH\x19\xd3\xca\xc8\x07!\
-\x14\xc9\x9f[Y7l\x0f\xb2\x91\xc1\xc7\xf8V\xa6\x85\
-\xd9T:\xad\x8c\x8b\x0b\x19\xc7qZ\x1ao\xe3W\xc6\
-\xb7\xb4\xb0\x12di\xb5\xa5M\xd1\x8aYH\xd43V\
-W\x89\xceV\x88\x86\xdb\x1ai\x98\x81\xb7\x91\xb8\x12\x92\
-\xb8\xb4\x97A.,2\x81\x22\x08\x06\x88\x13\x06*\xca\
-):Q(\xa0\xaa\xa9\xa3\x1a\x1a\x1e\xb5\xa1\x15TM\
-\x8dN`\x07RHW\xa2\xba\x04\x0b\xee\x8c\xe7\xa4\xe8\
-\x10\x5c\xef6%v=PO\x85\x83\xbe\xdb\x04\x0e\xb4\
-X\x842\x07\x97\x03\x9c{\x9bv}a\x97I\x07z\
-\x9b\x8b\xeb\xacG,\x07`b\x1f\xd4X\xe7\xb6\xf3\x02\
-\x08\x0a<\xday\xf7$\xb8\xbf\xc6f.C\x1a\x03\xa0\
-I\xec\xa8\xb1\x99\xdb\xb0\xc6\x88\xb3\xdcYc3\x8f1\
-\x1a\x9bU\x8dW\xd8Z\xecp\xcc\xfa\xc5\x19^\xd0\xee\
-k\x144|\xfer\xf73\xa0\x19\x83+\xf3w\xe1\x80\
-\x1dNi>\xa3\x99\xaeU\xe6\x188e\x9boE\x9c\
-\x9f\x9f\xedl@\xb2U\x939\xbfx\xb9\xbb\x01\x89\x8f\
-\xd1\x98qHc\x07v\x80\x9d5f\x1e\xd6\xf8\xe5\x85\
-\xce\x01v\xd6\x98u\x84\xc6\x22v\x94ua&\x12G\
-r\x8b&\x0ac4\x86a\xb7\x188\xe7\xf9\xce\x1a\x83\
-\x0dk\xcc\xe1\xe7ko\x87\x875\x868\xf6\xe9\xd9f\
-f}\x072\xd8A\xd6\x17p\x9a\x92\xf2\xc4J\x06\xa3\
-(\xb6\x1f5\x99z\xf1@Ik\x7f`Q5\x0cn\
-C*\xa2\x12d\x88\x93\xa9e\xb1\x0cC{\xfe\x9eH\
-\xfe\xcd\xec\xbc{\xbe\xb6\x03\xb0v\xde\x85\x01\x17\x0d\xa8\
-S;\xab$\x17\xef\x92\xdc.(TSb\xc4{\xa6\
-\xfe\xe0\xad\xcf$\x11\xea\xca\x9c:\xa5\x1cQG\x89R\
-7>n3\x9dz\xf0\xc2\x8b\xf5\x16^\xa9\x0eU\xb1\
-@J\xe6Ci\x979\x08\x98)5\x0e\xd7\x82\x91\xc8\
-\xdc]2\x03\xe0\xa1\xdb\xe8\xd5?\x96\x1b\xde\x1e\xedE\
-\xc3!-Z\xab\xe3\x00\x13\xa5\xe7\x1f\x12);\xc8\xdb\
-o(\x82\x94\xc04\x81b\x98\xac\x12\xcf\xfbq\xd9\xb9\
-n\xc8\x22b\xa5n\x1c \xf3C\xe2\xe4\xf0\xb1\xe3\xc4\
-%\x0dA*LQ\x885\xc5?(L\xf43L\x9d\
-\xc0\xad7\xa6\xab\xaf\xe4T\x0b\xb7\xba\xd6\xed\xed\xf5\xd5\
-\xcf\xda\xdd\xe5:\xb6DF\xf1\x0f\xefqM\xb8W#\
-\xa9{^\x8c\x0ap8Rw&,\x91\x1d\x1f\xd4Z\
-#i\x15\x85\xe2\x14\x19z\x10\xfb\x99\xf0\xc1\x9d\xa8\xb9\
-\xf4*\x1f\xd0\x99\xb1)\x90\xe6\xaeu\xf6\x14\x8a\x06\x98\
-x\xb5\xc1,\xc9\xc2\x5c\xd7\x91D\x14c\x96\xf8\xa8\xba\
-Q\x0a\xdc\xe5p6\xeb,\xbf$+\xc9f\xab\xcb/\
-E\xdc\x8d\xaa\xceT\x802T>\x9cFL\x8c\x87\xf1\
-Od\xc4F9\xc1\xba,O\xb3\x10i\x80w\x0fH\
-Mg\xc2Z\xf3\x95\xe6\x11\x05\xb1B\x14\xa1\xf9AQ\
-\xe0\x03\xa1\xc0L\xd4\xa2P\x12\x15R:h jq\
-3\x8f\x8a\x06\x16\x08I\xa8\x11$c\xe1\x0e\x0d-=\
-8#\xe9\x81\xc1`b\xef\x05C\xb8\x9e/hPR\
-\x94\x14\xab\xeb\x02-\xc1\xa0\xb5\x07i\x88\xaa\x0d\x0f\xe3\
-\xf8\xe1\xfc\x10y\xc0.\xed\x15\x8a\x00\x81UOeR\
-\xc0\x0d\xa5\xbe\xd4\xa845\xd4\x87\x92F\x84r\xe0\xe3\
-\xf7(\x13zO\xf1\x87<\xc0j\xda\x82 \x10\xa1\x13\
-(A\x01f\x8b\xf7\x0bf\xe2\x92\xd6^F\x183\xf9\
-\x04\x13\x8b\x88\x11O\x8c\x0a)'\xd8P\xf8\xd1\x8e\xf5\
-\x8c\x0b\x08\xbak}G/%=\x05\xa2\xbe\x93\xe4\xa2\
-\x8a\x84\xf5]\xbfb\xd1\xa4\xcc\xfa\xa19.\xe2\xe2F\
-\x0b\x80\xcf\xae.\xdf\xfcuv\xff\xba\xbd\xf9x\xbdy\
-\x12\xff\x91\x8a\x91\xda\x1d0o\x9a\xcb\xee\xd0\xbf]\xcf\
-{\xf5\xe2\xed\xed\xd5\xaf\x7f\xb5\x8a2#\xf3\xf3\xdf\xb4\
-w;\xb3\x00w\xf7\xb77\xdf\xcc_\x5c\xdf\x5c\xcf\x1f\
-\xae\xa7\x8bO\x12\xbc@+\x92\x0a\x00!\x8f7\xda\xfa\
-lj\xfe\xc5\xed\xcd\xdb\xeb\xf3n\xe6\x7f\xdf\x5c^\xaf\
-\xe6~{\xd9\xac\xeb\xbd\xbal\xfe\xf7\xe2\xe9\xf1\xf3\xd9\
-\xdd\xeb\xd9\xed\xed\xec\xc7\x07i5w9\x07\xf1B\x0a\
-\xeaC\xf6\xda\x17\xa1\x1a\xbd\xffr2\xc5\x90\xe2l\xa2\
-\x13\xf2\x92\xc2\xae'\x9f7\xb9)%]\xdd\x9er\xf1\
-dJ\xa0\x85@\xcd'\x8c%0\xd0\xad\xc9D*\xe9\
-@6\xe1,\x1a\xe4F-\x03\x22(\xe9.1\x11/\
-\x1a\x99\xc9m\xa6\x94\xd0\xd4\x89F!\x22\xc3\x87<\x83\
-$\x9fX\x14\xf7\x14\xc8\x93\xaf\xba\xd9i%\x88@\xb0\
-e[\xb3\x11\xa0\x84\xb3G\x9b\x89\x85U\xbc\xcd\x94\x82\
-\x14\xd4f\xa2\x17\x86&\xd5\xcc\x96/*\x15\xb4\x8c.\
-m\xab\xafDA\x0c\xe4.\x0b\x14)al\x5c\x85u\
-3k\xc1\xbe\xeafW5>_f\x1b\xb2<iL\
-KY\x92*\xd8\x85\x06\xd5\x8a\x02\x99\xac\xc2\x88&\x85\
-\xcc\x89\x9e \xc7&\xd3\xa5H:\xf2c\xe5H\xbe\xb7\
-\x1e\xffu\xb2R\xbf\xc2E\x02\x01e\xc1\xd8\xa3p:\
-\xe4S\xb6\xb6\x99T@\x02}\x22Z\x12\xbdek^\
-\xd0#p\xa2P<\x9c\xd4\x96\xe5\xa2\xc2\xe6\x9c\x13\xd5\
-\xa2\x19\x16\xad\x0aY\x92\xb2!5,\xc1\xccA\xcb\xcc\
-\xf6\xa9E\xf5B\x02\xd0\x02.\x82,\xea\x04\xd8\xc9\xfe\
-\xfc!\x1b\xc5\xed\x89\x05\xb6\x99^\x10T\x1fEy\xb6\
-yT(\x05\xe2\x9db\xa5\x17!qzP R\xdb\
-L,\xe0\x1aO\x9a\xf2\xfbQ\xf9Wg\xba\xae\xf5\x00\
-\x8c\xcb\xc8\xa7\xbbI\xe2\xfa\xe6|\xden\x94\xb8k|\
-\xc6\xdd\xd9\xe2\xef\xee\xe1\xbf\xe5\xcc\xde\xa3'9\xba\x9b\
-\xaf\x0eh\xbc\x9b\x87\x22i\x08j\x13(\x22\x90A\xd9\
-\xfavg\x03Mi/\x97\xce\xdf&\xd3\xcc\x82\x82\xe2\
-\x93XDj\xa0\xb1\x8d\x9bw/\xca\xcc\x8e\xef\xbay\
-\xac\xeb\xd5\x22\x0a\x08\x05\xe4\x87p\xf3\xac\xd5\xcdoY\
-\xbf\xeb\xd6\xe1+\x8e4\xbd0a\xe0\xaa\x1f\x05/j\
-\x88\xd4\xf5\xa3\x88^<\x11\xb8\xebG\x91\xb4\xa8\xaa\xd1\
-;\x0e\x80\xb9\xa8Q\xc8\x8a\xb3`/\x22\x12V\x1d\xe9\
-2\x13S\x8cW\x1ci\xcd\xee:\xd2\x9a\xbd\xea\xdb\x98\
-K\x0a\xbc\xe3\x05)KDp\xae:R\x93\xe2\xaa\xc4\
-\xba\xeaH\x0d\x8a\x03Kj\x97\x85\xb6\xc5\x8dL\xad\xc2\
-\xba\x99]GZ\xb3W\x1d\xa9\xb6\xc5\x0d7\xedzR\
-\xc3\x02\x01\xee\xda\x05\xc7\xb2@\x04\x00\xae\x02\xe9VB\
-I\x03\xbb\x9e4\xbc@\x90\xa4WOZ+r\xc5\x91\
-\xd6\xecU?\x9aP2H4\xba~4\xa4\x18\xb3\xb2\
-V?\xeaY\xdc\x04\xddV\x1d\x96KI%\xd7\x8e\x1b\
-u*\x8a\x8a\x9e\xd5\x8d.2E=YV\xdd(\x12\
-\x15Tg\xef\xba\xd1\x87l\x00\xa4\xae\x1bE\xccb\x09\
-a]?\x8a(%<E\xde\xf1\xa3\x08\x05\x10 V\
-\xfc(p1C\xb4\xeaH+*+~t\xdb\xd8)\
-?\xbd\xd8\xe9\xdf\xe5\xe5\xf3\x83zy\xc4\xe2d\xc1\xfa\
-\x11\xb8\xf9\x8fk%;\x11\xd9\xff\xf7K\xb9\x8d\xf2\x90\
-K\xb9\xc7o\xb4Kz\xdce\xe7\xa4\x13d.\x00@\
-\x13\x82\x12n\xd4j\xbaDW\x0bv\xbei>\x85B\
-(Q_<\xc6\x93\xc2\x8f\xca\xf4|\xee?\xa8\x7f\xfd\
-\x86\xd3\x17\xc8_\xac\xbde\xee\xfbf}H?+\xd6\
-\xdf\x7f\x8e\x9f\xbf\xcb\xaa\xb0*\xf7\xf3\xb3~~\xf0e\
-*\xc4\x1a?\xc3\x94~~\xb1\x81\x1f\xc4\xe7\x00k\xfc\
-\x5c\xbd\x9f_\xc2&~\xfe\xfb5~\x0f.\xb7\x1a\xcd\
-.\xab\xc5\x80zv\x99\x83\xecp\x98\xd2\xf9|>t\
-\xdaI\x97\xb5\xedp\x84\x07\xcdc~\xbe\xb6rb\xc4\
-\xfa8\x83}6\xdd\x1b\x1d\xf6\xf0\x97.k\x19q\xb6\
-\xd4h8R{4N\xdf^c\xe3y\xee\xa0q\xe6\
-\xbfQc\x91\xdc\xc3\x00Dq{8`\xf1\xb7\xfd\xe1\
-b\xdc\x03\xc7\x00\xeb\x0a\xc7\xa8c\x17\xc8Y6\x1f\xbb\
-`\xd2\x9e\xba@\xc5\xda?\xef;{\x01)\x9a[&\
-\xfb\x1e\xbd\x00\xf5\xe9\xbd\xce]\xa8\xdb\x18\xa1 Ag\
-[\xa7qAM`]y\x87\xeb\x085\xf2\xa94\x83\
-\xeb{@\xb9\xfd{\xecP\x093E'\x88\xc5m\x22\
-%\x93\x84l\xcc\xb1\xc9\x1c\xc3{y|\xff\x03N%\
-\x0a!\xa1b}e\xa2E-\xba\xf0X\x96$\x86\x88\
-\x95]\x06\x9cd\x1f\x03<0\x1a\x9e\x9f\xb0\xf1x\x0c\
-\xa2\xc3\x86{\x1b\x8f\x14\x0a\xef\xc2\x93\xd8\x96\xda\xc1\xba\
-K\x0d\xea7\xf5\xdb\xfb\x1eJ\xb2\xc5fi\x82\x09\x8c\
-R\xdd\x06U\x17\x80\x9f\xa6\xea2B\xf5\xc11W\xdd\
-\xa6\x93X\x02\x14:\xc3U\xf5\x02\x1a\x8aR\x07`Y\
-@5 \x9f\xc6\x0d\xca\xc5\x18hx4V\x143%\
-'^X1\x89s>\x8d\xc94\x0a\x18\x93\xb0\xb6\xbf\
-\xb0\x90;!\xcadJP\x88\xc4\xc9\x9aK.\x99f\
-\x9c\xfb\x0f\xda\x88\x9d\x86\x9b\x8e\xc4\x9e rQ\x0f$\
-\xad{\x0b\xa5(#i\x1d\xc4b\x97\xe4\xec]\x92\xb3\
-.\xc9\x00\x90V\x14<\xc3\xf2ax\xab\x08\x89>\x99\
-\x1a\x97\x16<\xc3\xc9\x94\xa9\xa4\x03\xa2\x8eB\xec\xa8\xae\
-8\xad\xb01hg\xe5R\x14\x03\xc3\xce6B\xa6\x02\
-\x8aa\xb5\xd5\x09\x17\xcf\x04\xb2=}\xb1\x17\x1533\
-?\x8c?\xb6m6\xb6\xcb\xdeF\x85j\x1d\x9bB+\
-\x10VM\xca\xb1\xb8+Q\xdd\xad\xda\xa58\xebR\x0c\
-O\x22\x98B\xa04H\x91a*\xd0d\xda\x82\x06\x98\
-!\x13.\x9c@\x086A/\x0c\x09\xd6\xdcV/\x96\
-L\xe3\x1a\xa5\x0d;u\x8b\xdc\xdb\xa9\xb7pdp5\
-\xb1\xb4\xc2\xceH\x5c\x9d:A\x11\xf2\x1a\x0cU\x9aA\
-\x13CwR\x89\x87f\x08\xee\x84\xe1\x13+\xaaJ)\
-6\x99JIAs\xc0Q66\xec\xfd\x15\xf1\xa7c\
-c\xcc\x07\xb61\x1a\xb61\xdb\xdb\xc6(J\x0a%\xd5\
-5Jb\x85HS\xde\x99\x89\xe5\xf0\xea\xc6\x1c\x8b\x91\
-\x09\xc8\x9e6\x86%\xc4\xc8\x95\x0fec0lc\xc0\
-?w\x8e\x151\xe1m:\xc7\x9f=\x7f/~8\xd6\
-\xf3\xff\xf4[%\xc76\xad\xf2g\xcf\xdfgc\xac\xc7\
-\xf0\xfc\x87\x8c\x0a\x0e\x14\xa9\x8c\xb11\x1a\x19]\xfc\xf4\
-\x83|\xda*\xc8\xffy\xf8\xbd\xb1-\x92\x8c\x18~\x0f\
-\xb4\xc5\xe1\xa9\x97\xf1\xb3<c\xec\x07GL\xdf|\xda\
-\xaac\x1cU\xf5\xf1\xd3\xb0\xe3'\x85\xc7\xa0\xa3\xa3f\
-s\x8f\x8f\xce\xf87\x0a\xa3\xe0\x19\xf1\xa6\xe4\xa7o<\
-\x90\xc7@\xe7\xdf\xe9.8$\x8e9\xc7\xefZ\x9c\xc2\
-\xb9\xb3\xad\x0e\xa28\x88p\xd5\xc9\xaaBT\x1c\x00M\
-\xc7(d\xc3\x0a%\xef\xab\x10e\xd1`\xd4\xce\x89\xc7\
-Y \x08\xbdV\x92[1[=!\x0a\xad\xa0\x90\xd1\
-\x18\xbd\xb6\xe8\xcd\xc3\xf6\xd5+l\x11\xe8zV\xe3\x83\
-\x22\x18\xa8T]NafJ\xc4\x07\xbd*\xcd(\xbd\
-h\x84G\xfeX\x1b\x15|\x98\xb7G\xc1E\x11C\xad\
-\xbbu\x89\x04\x11\xb3\x86\xafV\xc8\x05\xb53\x88\x84\xa2\
-\x16.8|\xf2\x06QF\xda\xc3\xb8\x8a\x1c\xc0\x01'\
-S\xa2\x92\x14\x99\xb6\xb8DO\x8c\x18\xb1\xb8/8~\
-~O\xb4#bv\xc4\xa90)\x9a\xec\x150\x91\x82\
-\x99a^\xad\x8c:$gk$g\x1d\x92\xe1/\xec\
-\x98\x01\xa9L\xa0hcNE\x83\x04\xd4'R\xc4)\
-\xd4c\x82$\x85\xcd\xbd\xc1\x0e#\x0b\xa59\x8f\xc2N\
-\x86\xb1c\xde\x13;/i\xd1\xc1\x8e\xa3\x88\xb0q\x17\
-\xbajh\xf5v\x076\xd2\xe1v)\xc8\xd1\x02\x02\x05\
-\x0d\xd84\x1b\xf8\x048\x09y\xc2\x85=\x0c\xad\x9d\x12\
-\x83\x82\xc9\x82\xb1\xf8\x96\x13\xa2j\x8e3;\x1a\xf6k\
-d\x1f\xd7\xccE\xf7 \x17\x19u\xa6v0l=+\
-1\xder\x22\x8b\xa2{R\xd7tB!\xb2.v_\
-\xa59\xeb\xd2\x0c\xda\x10e\xaa\xb0\xb66\xe4\x0a\x94\x18\
-\x13,\xa0\xee\xc4\xd6\x5c\x05\x13p\xdb\xe4p\xe1\xd3 \
-'S\x8a\x22\xe4\x068\xc6\x84h\x8bx\x93\xe3g\xcf\
-\xf5^\xecl\x1b\xcf\xf5\xf3\x0b\x90^\xfcd\x9b\x17 \
-?\xe3\xd7\x8b\x1f}\xc4K\x07F\xf8u\x82m&\xe4\
-\x7f\xb6\x8b>\xbb\xc0\x18\xf1\xd2\xe7\x13\xc4O\x0f\x8d\x9f\
-}\xc4\xcb%\x8e\x1fV\xa1\x1c\xe6\x9dk\xfd\x5c^\xf7\
-\x8bx\x0fN\xeb\xf5\xfc\xf2\xd5\xeb\x86\x1e\x8bf\x90\xe9\
-\x12\xce\x87=Y\x99\xf8\xb4\x85n\xb1\xfb\xb3\xa5K\xe0\
-d\xc0e\xd9\x16t\xa2\x98\xa6\xe0\x1b\x8b\xb2\xf6\xfd\xbd\
-\xfe/\xe8\x91\xbc\xf7\xeb{XX\xdc\xd4\x16\x05\xdf\xa8\
-t\xfd\xfc^\x8f\xf6\x16\xf8\x8e\xf6\xa8\x9eB]\xed\xc1\
-#\x1d\xc5pU}\x12\xf1\xa0\xae\xfaH\xc4\x89\x07S\
-\xdf\x82{>>\xc8\x84\x892^{e>PY\x95\
-\xb5\xa7\xaa\xc0\x00Xu|a9\xed@\x85\xe5\x8c\x1e\
-`%w+\xe8\xaa\xa3\x1a\xf2\x9e\x18l\xb8\x9c,\x9a\
-b\x11\xa34\x9fO\x97>\xd4h1\x0f\xe2\x854\xb6\
-\x0d\x82\xeb\xd1\x07D\xa9_\xe3\xd7O}\xc0\xd4\xc0\xa3\
-\xb0\xd6a5[\x16%\xa1\xc7\x8d\x97\xa4\x5c\x00\xa3n\
-\x0c\xae\xcf<\xf5\x0bdZ8{>O\x1e#w'\
-\xf5lNB\xd8\x7f\xa7V\xe5;{\xf1\xed\xe5\xf9_\
-\x9bM\xe7\xf7\x7fkn\xeeX\xd0a\x0eEG\xf0\x18\
-T\xeb\xcb\xc5\xdfV{,\x87{\x9e\x90\xc9\xd4\x5c\xea\
-\xcb!s\xa9\xd3\x07\x1c\xc5\x9d\xb9s\xbcY\xd6I\xf9\
-zw\xef7B\x89\xf2^\xe3\xa1D\xeb\x07\x80\xacM\
-C\xa7D\xf7\x18\x10%F?k\xc66\x0d\xb1.\x88\
-$\xbd\xfci\x83\x05\xc9y\x9b\x06\xf9\xb3\x8b\x02\x00\xf6\
-\xcb\xa0~\x19\x0am\x1a\x94!\xc4\x90\x99\xd9/C6\
-\xc8\xf06\x0d\xcb`\x8b\xcd26T\xb3I\x9b\x86e\
-H\x0e\xe8\xb1\xa1\xbe]\xdb4,\xc3@{\xf9\xf3\x86\
-\xfa\x8eY\x9b\x86\xf9;\xe2F\x1dxC}\xcf\xb8M\
-\xc32\x02e\xa3Mq\x7f}\xdf]^}7\xbf\x1d\
-\x16\x91\x88\x9bEl\xa8\xee\xf3\x8b6m!Cx3\
-T\xb1\x01\xaa\x8b&\x0d\xcbPt\x09\x8f\xe8\x95!\x1b\
-\xaa<\xa5M\xc32\x98t\xa3\x1eB\x1b\xcc\xf6\xacM\
-\xc32T137\xe8!\x1b\x9a\x9f\xb6iXF\x88\
-\x0a\x98\xf7\xcb\xd8P\xe7Jm\x1a\x94a\x10\x06\x00\xd4\
-/cC\x9d\x0b\xb7iX\x86\xa0m\xb4]\xc5~\x19\
-\x9cm\x1a\x96\x91\x14\x1aD\xfd2x\x83\x0c\x1eV\xc2\
-9}c\x85\xab\x8e\xee\xfb\x22#2\xd3\xfbe\xf8\x86\
-\x06h\xb3\x98\x0d5\x8e\x9eo\xef\x8c;\x84d8\xfa\
-\xb9]~\x92R\xc5\xac\xb3v\x91J\xa6\xad\xac]\x8c\
-\xe2NJ}\xcb\x06\xc3\xed\xfd1Mxl\xf0~\xd9\
-\xa6}c\x9a\x88M\x87ax\x9b\x06\xeb\x15$\xa5\x9f\
-?\xf5\xf3\x7f\x99m\x1a\xe4\x8f \xd9\xcf_6\xd8\xcc\
-\xbcM\xc3\xfc\x85\x09\x93\xb8_\x86m\x90\x91M\x1a\xd6\
-\x81P\xad\x9f\x7fl\xb2\xfb6\x0d\xf3\xb7\xb4M\x9dB\
-\xe4\x86z6o\xd3pl\x99\xb1\x81?\x1d\x80\x7fn\
-\x8c]#7\xc5\x95\xd2\xa4mb\xbe\xe0\xcd8m\xa8\
-k\xc16\x0d\xcbH\xd5\xcd26\x8d#\xb4M[\x04\
-\x01\x19\x91\xda\xefK\x01F\xfbkuHS\xe2~\x19\
-\xb4A\xc6\xbcM\xc32R\xa2\x9f\xff\xa6\xfa\xbeh\xd3\
-\x16\x9d\xb3n\x0e\x00`C};\xb4iXF\xf2\xe6\
-\x18\x1cb\x83\x8c\x97m\xda\xa2\x7f\xd6\xd8\xd8?#l\
-\x90q\xd1\xa6a\x19\x03>$\x91F\xda\x14\x1ek\xee\
-\xc1#\x0b\x12\x81o\x98\x810\xf7\x12\xee\x80\x87\x9c\x87\
-\x08\xa3\x9e>\xdbd\xf4`\x1e`C\xa7a6\xda\xe1\
-\x22K\xf4\xf3\x8f\x0d\x1d7\xb5i\x8b\x81#\xf7;s\
-\x87\x0d\x9d\xdelx\xe4k\x94\x1b[D8m\x10\x80\
-m\x1a\x8eX\x95bc\x8f\xe4\x1b*9\xcf\xdb\xf4\x11\
-G\xacV\x80X\xea\xd2;\xc5\x82\xc0J\xefD\xac\xcc\
-\xd1\x1b\xb1\xaa\xf4X\xbf\xda\x86\xb0\xf2e\x9b\xf6\x8eX\
-u\x83aR\xb4i\x9b\xde\x937\xf5\x0aa0\xa2^\
-G\x9fd\x97\xb2\xcf\xb9ni\xdbO\x9c\xf3\xffk\xef\
-\xca\x9a\xdb8\x92\xf4\xf3\xfaW0\xfc\xa6X\xaa\x94\xf7\
-\xa1\xf1:B\xa6\xad\x89\x89\xf0\xecN\xec<\xec\xa3\x83\
-\x92@\x8df$\xd3AQ\xbe~\xfdVv\x03l4\
-\x89&\x05\x8a\x1c\xcb\x07a\x19\xa8\xaf\xd1\xd9\x95_\xe5\
-U\x05\xa0\xcb\x8f\x85\x9e\xbf\xff]\xce\xe2\xfd\xd7\xce\x9f\
-\x9d\x9c\xe8\xd55\xf9\xdb\xdf\xe4\x8c%n\xc1\x06+\xec\
-q\xd3\xbf\xdeg\xdc\xd1\xe5\x05\xc9\xb4\xcf=\xce\xe4\xc5\
-\x9d\x92ax\x1b2\x8c\xdf\x9f\x8c\xd5\x8b\x93\xda\xc4\xf3\
-=M\x83M\x17\xd8X\x12}\x977\xc0\xe3\xb0\xdb\xd0\
-\x11q_w@\xe4\x84_\xf2~\x80\x00\xb7\xa0C\x80\
-\xf6\xb0\x0e=9\xd9\xe3~\x80 \x0bt,\x8a\xbeK\
-:\xc8nC\x07\xeda\x1d\xe5\xdf{\xd0\xc1\xb0_\xe8\
-\xb8[:8nC\x87\xc0>t\x10\xeeA\x87\xec\x15\
-I\x09\xef\x96\x8e\xe4\xdb\xd0\x91z_\xb1C\xd2\xffM\
-\xb1cY\xe7\x05\xae\x14\xf8\xe6}\xc9\xf5\x04/\xcf\xf7\
-o\xd8\x7f\x97\x15\xdecWi\xe1\x14~~\xbdd\xbc\
-*\xd9?\xc06\x14o\x93f\x15y/W9\x86\x17\
-\xefk\x1b\x8a\x0bivY\xf4\x1d\xba\x8aY\xde\x82\x0e\
-s\xbc/W1\xe7\x8f\xd5U,\xf2\xc6\xdd\xb9\xe1\xe4\
-$`OW\xb1\xac\xba\xf1\x16\x92\xe1&W\xb1\xe4\x0f\
-\xb0\x0d\xc7\xdb\xd4\x1c\x8et_\xb6\xe1(\xbf`\x09\xe6\
-\xcc\xb7\xa1\x83\xf5\xbeJ0g\xdf\xaf\x04\xbb\xe3[2\
-3`\xfe*o\xc9|\xfb\xfd>\xa6\x1d\x12\xfc\x9b\xc5\
-m\x15\xfcNvr}\x88\xd9\xb2\xfe\xea\xe6&\x0f\xa6\
-\x1fM\xc2\xd6\x86\xeaH\x8dA\xfcb\xdd\x87\xb3\xa9\x86\
-\xde\x91\x8aq\x8d\x8a\xfe\xe9]l\xf8\x10N,\x9b;\
-\x14\x04\xf6\x07\xd5\xafz\x9aqP\xfd\x10\xd6Z\xb0\xd5\
-c?\xfd\xe7;\x8a\xde\x9e\x80\xfcf1\x15x\xee\xb1\
-\xdfdJc\x99\x96\xabK\x87\x0elm\x8b\x1b\xd6\x94\
-u\xda\x147\xa5\xb7\xcd\xeeH\x0d\x84e=\x02\xf7\xd1\
-C\xb7T\xe0Y\xef\xc3t\xd6\xfbj\xdfQ\xef\xf1\x9a\
-\xde\xf3\x1d\xf4\xde\x1b%O\x9d\xd7j\xdeU\xdf\xe9\x9a\
-\xbe\xeb>}\xb7\xad\xbe\xcb\xd4\xf7h\x00@S\xe7m\
-h\x8fQ\xfd\xc5\xea\xe4\xed\xe7\x9fM{\xa2\x1d\xbfY\
-\xbd\xf8\xfe\xd5\xea\x87\x99\x22?\xbc\xfa\xf6\xc5\xe9\x0f\x0f\
-7_e\xb7\xf0Ow\x1d\xdf|\x81\x1d\x88.E\xfc\
-\xe3\x97\xab\xbe\x01S\x7f\xcf\x7f}\xba\xe3\xd0:\xd3\x0c\
-\x9fx\x8c\xea\xbe{\xd5\xb7f;}\xbd\xea\xf1\xe0\xf9\
-\xaa$n\x0e\x9c\xf5K\xec\xc0O\x9f\xfd\xb3\x13\xbd\xeb\
-\xc8\xb3\xd3\xb3\x17\xab\xb3\x8b+\xe0\x0c\x1e\xb2^\x1f\x07\
-\xab\xbf\x91\xbc\xea\xcf\x06\x1e\x8b\x83\x8b\xb1yv\xdc\xb9\
-\x9eu\xfe\xe7\xd3\xd3\x1e\xaa\xa8\xa9\x12!\xeb\xfc\xe0\xf8\
-=\xe7\xa6$pe=\xb7V\xdb\xa9\xa9G\x04\xed\xa4\
-\xb2b\x98\xc1\xceC?\x95X\xbf$\xf0\xdd\xd9Y7\
-\x8f\x87\xaf\x8f\x7fZ\xf5\x9e\x7f]O\xdf\xac\x13\xdd?\
-N\x7f(\xda*k\xbc[MPQ\xfcv\x02'Y\
-\xc3\x91\x87\xcf\x9e\x9d\xfe\xb8>\xba\x95\xeaK\xd0T_\
-\xfc\xb9\xb7\x9e\x9e\x9d\xbe\xf9\xdb\xd9\x0a\xc4\xfe\xbe:?\
-\x7f\xf5\xed\xcb2\xf3\xfa\x1b\xf3\xea\x8f?\xd5)kh\
-L\xf8\x95\x8b\xbf\xfbq\x06\xfd\xb4\x0d\xbd\xedc\xd5\xe5\
-\x14{\xcd\xcc\xfc\xf2\x81\x9f\xae\x1c\xd8\x8c\x17\x00\xf4\xfa\
-w\x0d\xae\xde|\xb7\x13\xdf26\x9a\xde\xba\x85\xca\x84\
-\xae\xaf\xd8/\xb8\xc1\xbe=~\xf6z5qY\x7f\xdf\
-\xbfz\xfb\xaa\x83#6:\xd5Uw\xfa\xfc\x93\xcf\xde\
-\xac\xce\x8f_\x1c\x9f\x1fo\xcci\xd3\xee3\xebO\xfe\
-\xe3\xb3o\xdf>~{\xf2C\x7f5\xbe|\xfd\xea\xf9\
-\xeam\xb5\xa6\xe6\xe0\xbe\x9b\xc2\xb0H\x9c\xff\xbc\x84b\
-\xfa\x11\xc9\xd4\x1c\xce\xfc\xcb\x97\x1d`4\x17&\x96\xea\
-b]\xe6\xd1t\x9d\xed\xab\xfe\xfd\xf4\xdd\xd9\xf3\xd5\x17\
-\xb5\xa3\xda\xdb[\x5c\xb2\x5c\xab;\xe2\x9b\xafW'\xe7\
-\xff3\x0c\xeeD\xcc\xfa2\xa7\xdf\x9d\xf7\xdd\xd9~\x1e\
-~\x1a\xb16\x9aI\xd5\xf3\xe3\xb3\x97\xab\xf3\x0d\x5c\xf2\
-\xe6H\xe92v\xa3\xffRb\xf5\xb4\xd7\x0a\xc7\xbd+\
-\x7f\xfb\xef?\x93\x8c\x8dbs-k\x0b\xad\x13\xaaj\
-\xea#\xda\x1d\xa5\xfb\xdf4\x82\xe3/.jPO\x8e\
-_\xaf=\xbc\x9fq\xbe:Z\x9b\xcf\xd3\xe1o\xc0\xbf\
-=\xfd\xebtdz\x7fw\x9e\xdas\xee\xf8\xf9$e\
-\xe8E\xb1<\xefG\xc1\x05N\x8a\xdeB\x7f\xb44g\
-%\xc5\xdf\x22\x11\x05/[I\x1d\x1b=\xe5\xb3\xb3\x17\
-'\x8f\xff\xf7\xcb\xa7}s\xd0\xe7\x8f\xff\xef\xf4\xec_\
-\xa3;\x16z\xfc\xec\xf4]'\xa3G\xae\x17\xcf\x1f\x9f\
-\x8c\xd7{\xf5\xa6G\xf6Go\xbf\x7f\xf9\x9f?\xbey\
-\xfd\xd9\xa3\xe9@\xbd\xa7\x82U\x9d\xbe\x11p\xb6z[\
-n\xd0\x9d\xfa\x1f\xe7\xe7\xdf=~\xf4\xe8\xbb\xbe\xa9a\
-;={\xd9\xcf\xeb\xff\xbdyU'<\xfa\xfby\xdf\
-\xd0\xf0/%wt\xfbu?\xfa\xab\x8b\xae=\xdax\
-\xf9\xe7\x9f|\xb2\xab\xd8\xee4M3\x85=\x8a\xd7\x9b\
-\xab\x82\x22~\x9c\x0f\xceg\x95\x8b\xabw\xec\xb5\x91\xd9\
-4s\xc4\xaa,w\x0ai\x80\x8aK\x920\x8c#\xe7\
-\x92bY\x92j,IR\x8d\xa3'1\x93D\xb0,\
-)M\x96$E>yz\xc4sI\xb4(\x09Y}\
-I\xd2\x17|t\xf4\xe5\xa5>\xc9\xb2$\xe7EI_\
-\xcaW\xf4U\xce%-3N\x90\xb9$\xe9\xab\xa3\xa7\
-\xf4T\xe7\x92bY\x92\xb0.Iz\xdaiz:\xb7\
-\x02\x86eIN\xb4(i\xf8\x9bK\x1a\x19\xbf\xfc\x99\
-\xf8M\x8e\x11\xfb9F\xde\xb5g(\xab\xaa\xcf5\xf1\
-\x91\x93\xddc\x8el\x86\xa2\xcb\xb6\x18O\xe2h&O\
-p#oa\xec)\xcd\x22\x96\xc7\xbf\x1es\x89\xbe<\
-jl\xbc<\xfe\xf5\x98K\xca\xbb\x1a\x7f\xc5EI\xca\
-\xb8O\x9f\x94\x17%\x85\xc8\xb2\x9f|q\x85'\xd5\x05\
-I\xb8(\x04\xbb\xdb\xf2\x5c\x88/\x19\xf6\xc2\x92\xe1\xb4\
-np\xff\x8b\x03;i\xdac\xd4\x8c\xf6e\xa8\xdcE\
-y.D\xd6\x0c\xcd\xf8\xb8\x91!\x84o\xeem\xdd\xe1\
-\xc3\x89\xc9; \xc6\xf1v\xc4\xe07\xf7\xb4\xa4\xf1\xc1\
-\xb4\xb8\xedK\x0b'\x7f\xc11\x17\x12\xb7\xa3\x85\xbe\xb9\
-\xb7\xd5\x92\xfd\x88\x89\x88'1O\xc9\xb1\x1c\xb4\x00\x9c\
-\x16%\x1d\xc5W\x91sI\xba,\xc9|1\x90>\xf9\
-\xe2\xc9\xd1\x93K\x92\xfc\x9a\x22H|I\xd2\x91\x1e\xd9\
-\x91\xcc%]\x93&\x10u\xb1\x08\xfa\xa2?\xe6\xc1=\
-\x97\xd3\x04\x03\xd2rp\xaf\xc7\x5c\xd22\xe3\x82\xd7\xa4\
-.\xef\x0f\x9bKZf\x5c\xcdsQ\xd2\x97\xf5\x98K\
-Zb\x1c\xf7\xf0\xb1\xcc\x05\xf7\xf8\xec\xe5\xe6m/\xd9\
-\xd6\xa1\xe6|\xe7\xdd\xb2\xb31\xb3\x1f\x22\xd7\xb3\x02?\
-\xe8s\xa5\xfa\xb9\xff8\x09\x9a\xd6/N_\xacj\xaa\
-\xd3\xbd\xe8\xf9\xfao\xb3\xbc\xb3\xebf\xc2\x82f\xe6\x9b\
-\xbd\x00X\x1d\x85\x0f\x1fR\xb6\xd4`\xee/\x11\x1b\x13\
-*\xcb\x83\xf9gP\x17\x9f5\xb5H\x8d\x04\xa1a\xb3\
-\xf8\xcdo\xde/\xef\x1c?\xceT\xc7\x8d\xe6\xc7\xd7\xec\
-N\x1b\x99]\xfd\xbf\x1e0\xb7\x08\x00\xe3C\xb4\x06\x9e\
-\x10x\xf0\xf56\x8a\xd9\xc0\x22\xbc\xa3\xc1M\xd36P\
-z\xdf\x15?\xa4!mA\x05\x18k\x07\xa2\x85z\x01\
-\xda\x00\x87\xb6\x04e\x89A\xf4\x96,\x87a\xcd\xd1\x81\
-\xa5\xcb\xa9\xe3\x0cY\x18\x0b\x15V\x88\xd2ah\x0b\xe6\
-9\xc0P@I\xaa\xb3\x0c\x91\x16:?\xa1\xe3\xfe\xfb\
-\xd3\xed\x1a\xd8\x86\x92f\x1a\xcc\xd9!\x9f1Tc\x01\
-\xc0XV\xa0 \xccV\x17\x99P\xc2f\xc2F\x1d-\
-:\x9cF\xc85ld\xc8a\x1b\x0a-W\x1f\x001\
-\x19\x81\x8e\x0f\x00DFIG\x82\xc6E\x91\xb7QJ\
-\x01\x0eY\x00!\x0e\xcd\xa4\x81A\xa0\xad\x16z\xf5b\
-l#\xeaB\x8f'\xf4\xe7%\xf3b\xb0\x90d\xd9\xd7\
-\xbcH\xf0\xc1\x9dY\xfe\xcd>\xb6\x19\xc1\x99\x16\xd5\xcb\
-\xb1SW?K\x9c\xd9\xbe6.\x92\xeb\x09\xa33\xb4\
-n#b\xcb\xcc\x01\xf1\xa2\x14\x80:H\x07G\xd5v\
-\xb8hk\xd4`\x8c-l\x1eY\x88\x86m\x10\xc12\
-\xd2\xa4\x96(\x87\x1e\xeb\xa1Ln\x14YmB\xac\x96\
-\x1e\xfa v\xf3z\x1c\xc5j1\x8b^\xe9\xde\xd8\xde\
-e\xd1y\x1f\x94\xf9\x83K\xc3\xbe\xcd`V\xce\xc7C\
-o\x99\xa1e\xecM\x0c\x82d\x83D\x03Bv?\x8c\
-&\x9c\xcc\xb6\x8dd\xc0\xa8\x98\xb7t\x01\x8aC\x84h\
-\xacH\xd1E\xcd\xc0H&-\xe9\xc8\xe2\xda\xa1,.\
-\xb0#\xa9\xe4\x8a\x13\xd2i\xb2\x16\x89.>\x802\x8e\
-\x1aJ\xa2\xe2\x88T[\x00\xcdhhSjra\x1a\
-\xec \x03\x86H\xcc5\x06P\x97$\xae\xd1\x82(\x13\
-(H\xd3\xc8j\xa0\x22\xdd\x0a\xf0j\x98(9_4\
-9\x1cTG\x19f\x1e\x87\xd9\x00%\x8b\xa5\x0d\x12M\
-\x9c\xd3\xa2\x00\xa2d\xee\x080#\xd3Ad\xb3H\x88\
-\x09\xf9zN\xf6\x8e\xf17\xbcq\xfc'\x13\xa8\x0c8\
-\xe5@\xe3\xc9io\xfc\xf0|\xb2\x9f\x9d\xa1\x03\xff4\
-Y\xd3\xd5\x0fz\xd7\x0e8\xef\xb8\x168Y\xd5\xe8;\
-\x95 \xd6.S\x80\xd9\x000[y\x06\xb0\x1e&\x1f\
-D\xa7\x95\xcb\xee*m\xd8\x80t\x5c\xaa1\xbc\xb2:\
-V\xf6\x82u\xc6\x81G\x9d_\xd9\xaa\xc4USch\
-\x8e\xaez\xf9\xc2?\x17S\xb7W6p\xa7\xb2\xfe\x1e\
-\xcazd\x01C\x80\xf0&\x22]\xa9AY\x19\x95\x8d\
-\xf4\x01\xb1RvH\xbb6*[\xea\x80\xd6\x19\xa5\x1d\
-!\x96v%\xee\xde\x95\xe5\x9d\xca\xe6\xfb\x8c\xacr\x01\
-,^\xca\x06t\xd5tPVK\xa1R\x7fD\xea\xff\
-\xd5\xa8W\xa3\xb2^\xca\xd6\x19\xc3\xc8\x8a\x8f#\xab|\
-{e\xafQPw)\xe88S\xf0\xf2\x85\x8f.\x03\
-\x09m\x0c_z\x90\x1d\x05)\x0e\x00;\x98\xd1\xf4R\
-7w\xd05\x072\x1a\x0dV\x1e\xb1f\xa4\xc2\xa5u\
-\xf0\xf2u\xe7\xcd\xb5\xfe\x8f^.\xa4\x82\x1e8\xbe]\
-\x8da\xff\xec\xdd\xeb\xd5\xe3\xd5\xf7\xab\x1eJ\xea\x9b\x92\
-g\xa7\xffZm\xca\x81us\xfc8\xfb1~\xf7\xe3\
-\x06(\xea\xfa\xc7\xa0\x8f\x9f\xbd;?\xdf\xc6\xfe\xd9o\
-\xc4\xd4o\xc8\xd4\xeb\x845\xba;\xa9\xb8\x1d\x12TZ\
-\xa8\xe7\x1dq\xcey\xde\xfb\xad\x83d5#\xbd\xb06\
-\x90\xc3\x8a\x9c\xeb\x17%\xea\x17\xd7\xb3&$\xf3\xf9\x87\
-\xe0\xa7;\xcbP'\xfb=\x16\xea\xf70\xe1\xf9\x05+\
-\xd2\xfb\x9f \xdeG\x05\xff\xfb\x9a\xfeL>g\x9a\xb2\
-\xf7\x08N\x1e+\xbf\xad\xc9\xc5\xcd\xd3\x03\x22\xd7\x07{\
-\x10v\x953\xcd?\xa6\x13\x1f\xc3tb\x8f\x11\xa7\xcb\
-\x13\xc2q>\xf1\xfe\xf3\x87\xad\x99\x07\xa6\xf3\x94\xfd>\
-\xc2\x19\xc0\x95\x92\xcf\xac\xa0}\xebc\xa2\xc4\xc9Q>\
-\xaa\xfa\x7fYU\xe7[\xaa\xca\x93\xaa\x1fU\xf5\xbf\xac\
-j\xc0-U\xd5I\xd5_\xe1<`\x07\x13\x08x\x99\
-\x8ak\xd4\xf7\x07\xf3R|\x9e\x0fYn\xaa\xeb?\x86\
-r\xbcz?\x15\xe4\xc37C/\xfdp\xe2\xf5\xf1\xb3\
-\xd5\xeb\xf5\xb7E\x0f\xea\xd8\xae\xaa\xad\x06\x14\xfa\xa3\x9e\
-\xd5\x1a\x90\x99\xc5\xe1\x10\xf9\xa2\xccd\xbc\xc6\xceS\x1f\
-\xe2pf\x15E\x95\xa6\xaa\xc0\xc3\xe6(&!\xab\x87\
-4\x8b\x98\xc4\xa27\xad\xc0$(\x19\x13\xfeiN\xea\
-\xa4\xf65\x1c\x1b\xc7e\x8eK\xa2if\xda{1}\
-V_\x89\xdc\xa0\x03\xed\xaf_\xf5\xa7\xc7\xb2\xc1^\x1c\
-\xf7\xef8\x9f\x9d\x1d\xff4vmD\xaf/J\x95\xf9\
-\xc1|\xa2\x1d\xde\xa2R7\x8dQ\x02 %\xbd7\x8b\
-\xf8d\xad \x89n\x08X\x183\xa7\x8f\x95f5\xc3\
-+\x91R\xb5\x0c\xaa\xd5e\x904U@\x91C\xc3f\
-,H\xd9\xb1C\xa3\xe6!`<4\xcaK\xebY\x1b\
-\xa1&\xfb\xf6Y\xd6\xd84\x1c\xd7r\xbd!\xd5U\xc6\
-k\xa2Vs\x8c\xdd\x0e\x90\xc6\x1d\xb3\x06aX)\xac\
-1\x93\xb0\x0f\x18\x19\x90V\xc2v\x0c\x1fO\xd5\xe4\xa1\
-\x8f\x89\x0dA\xc1\xea\x8d\xd2\x92\x9c\xb4\x0a@\x000\xa1\
-\x8eqS\x0e\xc2\x83\xacFO\xf1\xf5\xa2\x84#\xe9\xd8\
-\xf0h`c\xa3\xcc\xd4m\xad|d\xa3L\xe8=p\
-m\x89\x1c^\x9c\x9a\xb9\x1a\x17\xe4\x9c\xae\x5c\x9d\xa7@\
-\x1aN\x14\xb0Q\xa1\xca?\x92\xccU\xa4\x80\x93K\xd4\
-\xf433Y\xa3.(\x86^YY\x0e\x03\x8a\x8f\xaa\
-\x88\xb8\xd98\x06,\xa3\xa0\xa2v8F\xb2\xeen5\
-\xa4\x0a\xb7I\x98\xe4\xa0\x1f\xf8\xc5E\xedPa\xe0a\
-\xbbs\x8a\x1b\xc2.\x948T\x1ax\x15\x9bT-l\
-\xe4\xbf\xb8\xa8\xb3.h\x92l\xc9\xbenp6\x8bM\
-\x03+\xb8\x8e\x94\x0b\xfaa\x8d\x02:*\xd5\xd0\xa8\x86\
-Q\xc7\xb8\x85G\x10\x96\x5c\x1fz\x84<\x8e~!\x00\
-\x1c\xce\x83Q:b\xd4\xe0\xa7:S\x87\xb0\xa5\x199\
-O\xb6\xbd#>\xb3b^\x80\xe77\xecT\xda[\xe8\
-\xec\x5c\xbb@4\xc8\xf1\xc0Cl\x88\x18H\xf2`\xdf\
-U0b\x83\x07\xef\x1dK\xca\xbb\xe7\x81$\xfe-\x01\
-d\x1e(\xcai\x1c$\xab\xd0\x0dI\x95u\xd5\x8d\x8a\
-\xeaC\x89\x8c\x9c\x96X\x96Qo\xd4\xc2X\xc41u\
-pM\x17\xc5\x0e%\xb9\x12\x0c\xb3S/\x87 \x1c\xa2\
-\x87\xb1\x00\x96\x9d\xa25#\xc8\xa4\x0a \xa2\xe8f\x07\
-\xa8c8\xe7\x8a#\x96 9\xc3\xa4\xec\x88\xc9\xeb\xec\
-\x09\xd5\xc6\x08\xa8\xbe-\xd1\x9aJD\xf8\xf6\xb5\xbd\xb1\
-\x99q\xb7\xcc\xa9\x9b\x95\xd7\xc1\x19ytj\x8f\xe0\xae\
-9\x124\x84\x90(2\x1c\x12p\x80(\x0dd\x98\x09\
-\x0a\x82\xf2p\xb2z@\x14AR\xfdA(4Z\x18\
-T%ZY\xcd\x85\xb4cuq\x8e5ff>\x04\
-*\x07\x8b\x9a\xe7Lh\x11\x9d@`34\xb4\x09\x02\
-H\xccP\xcf\x86\x12\x8e:C%Z(&\xe7\x1c\xad\
-X\xc7\xe84C\xd9[ \x88\xf8\x0cEj\x94\x1c\x94\
-\xa5W\xa1\x8eF\xe5nH\xce\xa6\x07\xa9M\xc1A\xab\
-fj\x00\x11\xaa\xa5\xbf&F\xd5\x9a\x0d\xd3\x82T\xc7\
-\xd9\xb5\xb99Z\x99H\x88\xa7QE\x03\x111+\xfb\
-\x920\xa2\xdcer?\x1f\xf4\x94e\xcd`\x88\x11\x84\
-\x8d$\x08J\xa7\x09\x15j\xa2\x9aZ:Y\xb4\x94\x0c\
-\x90-\xf4\xa8PJ7\xd0-\xd4\xbc\xb9\x93J\x14\x96\
-l\x9c<a3\x9e&t\xe2\xffh\x1b\xb5\x06`A\
-1]\xa70\x09'\xf3\xa9G\x13\xb6\xdd\xfb\x05\x14\xc1\
-\x9a+\xc9\x90p\xa3\x11\x09\x0aN\x96\xdf\xd1\x1d\xac\xec\
-\x0a{\x0ct\xf3\x07\x14\xa1\x7fZ\x9c\xb8\xb2\xd1\xc7\x1c\
-\xba\x96k\x1f\x0b\xbc\xa1\xf6qM\xcd\xb1\xf6\x910/\
-J\x19\x08T\x0a\xa3\xe0\x94\xa8:\xc4\xd4H\x0br]\
-\xf3NZ\xa4{\xac3_%\xa0A\xb0\xd6\xa1\xb1\xe0\
-\x88\x80\xd4\xa8Lg\x1e\x1eY\x98X\x92\x0e\x99\xce\x93\
-P\xf3\x9e2\x9d)\xdec\xa6[.\x9a\x97\x93\x9f\xfc\
-\x91\xfc\xfeH~\xf7\x93\xfcB\x9aY\x8a\xddmF,\
-\xb4\x83\x98\x7f\xe4\xc9\xdfI\x9eT\xc8Y\xac\x9bG\xd4\
-\xd0y|p\x9c2\x89\xe3\xd5L\xe2p5\x93X^\
-\xca$\x0e\x973\x89\xeb\xe5L\xe2z5\x93\xb8^\xcd\
-$.\x973\x89\xcb\x95L\xe2t5\x938N\x99d\
-1\xc6\xf3\xb5\xf5\x81\xfd\xea\xeb\x83\x9b\xf3\xe4\xc3)Q\
-\x226\xb7NX\xb4\x08\x17\xbe\xcdd0\xf6c\xec.\
-W\xee\xe6vL\xd2d\xed-\xe0\x5c\xde\xe2\xcdj\xf1\
-\xcdE\x98\xf3\x02\x80h\xa4\x1a\xd8\x81\xf9);\x5c\x89\
-\x98\xb8\xc0k?\xd5\xba\xb9\xae\xb8\xce\xe4\x1c~\x9d&\
-\xe7D\x97JR\xc468\xbc\xe6f\x19e{q-\
-\xd6\xabd\xb8\xb5\xb8\x16\xd3\xdaZ\xbd\x96\xe1m0\xfc\
-\xe1\xb4\xc26\x9d\xba\xb5\xc2\x96\xdb\x0bl\xc8\x0d\x18\xa9\
-#\x17\xab6\xa8\x0d\xd5\x0a\xbaXM\x9a\xf7oW\xe0\
-t\xd0\x0f\xf1\xa2l\x16B\xcb^t\x8d\x11\xd0G\xe2\
-EW\x9cf\xc9\xad&/\x1a\x01\x8f\xe6\x8a\x19\xba\x01\
-$+C\xa1\xd1\x15O\xdc\xc5<\x13,\xb1\xb6\xf7\x02\
-\xf6\xee@\xe5\xf2\xe0\x12k\x0dP\x9c\xd5o\xc9\xde\xb2\
-kp\xda\xdc5\xc6e\xc3N\x04\xd3\xb0\xca9_\x9d\
-\x85\xf1Yb}\xc0v\x12\x94\xf2\xde\xa6\x09-\x093\
-E\x0f\x1ffc\xb0\xb1\x0al\x99$d\xf9`\xb96\
-\x88\xd4\x0f\xec\xf7=\x8d\x9d\xfd\x02c\xf7\xe1D\xef\x9f\
-M=>\xe68\xa0\x8c\xa5\xa0qKd\xe3Z\x07g\
-lL\xaa4L\xe6\xdcI\x9c\x0e8\x9aJ\xa8\xc7\x10\
-\xc29\x01\xe4@\xac\x81&\x9a_`\x5c\xf546u\
-\x0a\xc2-\xd4\xb5%\x03a\xd6u\xc80C\xc7\xceh\
-\xb6\x84p\xe2\xdbE\x98H\xdf\x7f<\x02>\xda\xf1\x08\
-k\x8e\x95\xf3\x08\x1a{\x10nc\x12-D|\xf6>\
-\xcd\xc6\x86\x149\x96\xe2\x04L0\xce\xcb-\xc0\xa3\x06\
-\x03\x0c\xd5\x86\x94i\xa0\xc8| \xda\xdc(\xd1'\xac\
-\x06=\x9a1\x0a\xdb\x16\xca\x95\x03\xd3u\xc00\xc8{\
-'I\x1bE\xb8\xd6Hr*\xa0\xfc\x06\xec(\x11n\
-aG\xf4+\xf3k\x8a\x86D\x198\xd4O\xe6F^\
-c\x14\xe2$Y\x98eP\xd8\x01k3u-$\x89\
-\xc0\xa2\xc6\x92\x1aZ\x8ax\xa1\x0eb\xce%\xcf\x15(\
-\x0bbM\xe22\x0e\x19B\xe9p]!\x91X\xcfp\
-=\x0a\xa52\xc7t\xd0\x19*\xd9\x1c\x125g\xa8A\
-\x03%\x8f\xa1\x80\xa4&\x0cY\x86\x88\x8d\x9cI\xf1\xc0\
-\xbd\x05a \x95\xb93\xa1\x99\x0c\x13HL\x1c\xf5F\
-V\x87\xf5W4P!M\xea\x9d\x14\x0a)\x07\xc1\x0d\
-B\x98b\x90\x08FA{[R-j\xec&\xcb\x9b\
-\x00)p\x99.\x90\xa8\xea\x01gC'\xd5,\x0c\x01\
-\x1d\xfd@\xa0\xa5:\x04\x0f\x98\x92\xda\xe06\xd9\xea(\
-E\xa1\x90\x0eI\xa3DT\xb2\x01cp\xd3\xabW\xde\
-m\xd9y\xf1]\x88\xfaW7\x80\xf9\xfc\xff\x01\x9e\xd5\
-\xc9%:P\x01\x00\
-\x00\x00\x18\xd8\
-\x1f\
-\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xed}ms\xdbH\x92\
-\xe6\xf7\xf9\x15:\xcf\x97q\x1c\x99\xca\xf7\xccrw\xcf\
-F\xdcL\xec\xc6F\xf4\xc6]\xec\xce\xc4~\xdc\x90%\
-\xda\xd6\x8e,)$\xb9m\xf7\xaf\xbf*\x90\x12X\x14\
--\xd0l\xda\xdd;c\xb8\xdd&\x1eTUV=\xf9\
-\x06\x14\x80\xc2\xf7\xff\xf4\xe1\xed\xc5\xd1O\x8b\x9b\xdb\xf3\
-\xab\xcb\x1f\x9e\x11\xe0\xb3\xa3\xc5\xe5\xe9\xd5\xd9\xf9\xe5\xeb\
-\x1f\x9e\xfd\xf5/\xff<\xcfgG\xb7w'\x97g'\
-\x17W\x97\x8b\x1f\x9e]^=\xfb\xa7?\xfe\xee\xfb\xff\
-5\x9f\x1f\xfd\xe9fqr\xb78;z\x7f~\xf7\xe6\
-\xe8_/\xffv{zr\xbd8\xfa\xc3\x9b\xbb\xbb\xeb\
-\x17\xc7\xc7\xef\xdf\xbf\x87\xf3\x15\x08W7\xaf\x8f\x9f\x1f\
-\xcd\xe7\xb5\xe6\xedO\xaf\x7fwttT\xc5^\xde\xbe\
-8;\xfd\xe1\xd9\xaa\xfc\xf5\xbb\x9b\x8b\xa1\xdc\xd9\xe9\xf1\
-\xe2b\xf1vqyw{L@\xc7\xcf\xc6\xe2\xa7c\
-\xf1\xd3&\xfc\xfc\xa7\xc5\xe9\xd5\xdb\xb7W\x97\xb7C\xcd\
-\xcb\xdb\xdf\xaf\x15\xbe9{UK\x8f\x9dy/C!\
-*\xa5\x1c#\x1f3\xcfk\x89\xf9\xed\xc7\xcb\xbb\x93\x0f\
-\xf3\xbej\xed\xe3\xb6\xaa\x8c\x88\xc7\xf5\xd8Xr\xb7R\
-/>\x5cT&>\xd9\x99\xe1\xe8\xba\xf4\xca\xfeu\xfd\
-\xfbP\xe1\x1e\x80\xdb\xabw7\xa7\x8bW\xb5\xe6\x02.\
-\x17w\xc7\x7f\xfe\xcb\x9f\x1f\x0e\xce\x11\xce\xee\xce\xd6\x9a\
-\xb9'\xbf\x93\xdbi\xe4\xf2\xe4\xed\xe2\xf6\xfa\xe4tq\
-{|\x8f\xb7\xfa\x9d94\xa0j\xf8\xec\xeeM\xdd\xe5\
-\x1cv\xdf,\xce_\xbf\xb9\x1b\xf7\xcf\xcf~xV\x07\
-\xcc\x8e>\xec\xdfw\xe9\xc5CC\x08\xc2\xc3\xa1{9\
-\xeb\x87t\xa3\xd6\xd9\xd5i\xedY\xed\xf7\xeb\xab\xf9\xe5\
-\xe2\xc3\xdd\xfc\xa7\xf3\xc5{\xa8\x02~\xee\x9b\xb8zw\
-w\xfd\xee\xee\xbfj\x89\xc5\xe5\xb2\xad:\xa8q\x84\xcb\
-\xc3C\xbd\x07\xb0o`\xf1\xe1\xfa\xea\xe6n\xfe\xea\xfc\
-b\xb1\x14x\xfc\xe6\xea\xed\xe2\xf8\xfa\xfc\xb2\x8e\xf0\xe6\
-\xaa\xfe8\xbd=\xbe\xfa\xf0\xf1\xf5\xe2\xf2\xb8\xd6\xb88\
-yy\xb18>9\xbd\xab\xb2n\x8fk\xe7.Nn\
-W\x9d\xbb\xbe|\xbd\xb5\xe9\x0fg\xd7U\x8d\x1e`[\
-\x0f\x7f\x1c\x0f\xff\xb1\x1e\xff\xfe\xed\xe2\xee\xe4\xec\xe4\xee\
-\xa4\xfe^\xd1z\x8fh\x0c%j\x99j\xb4/\xfe\xfd\
-\xcf\xff\xdc\xf6\x86\xfd\xd3\xd3\x17\xffyu\xf3\xb7\xba\xbb\
-\xdaZ\x81\x93\x97W\xef\xaa\x82\x86:\xabrg\xa7/\
-\xaa\xe1\xbc=\xb9\xfb\xe3\xf9\xdb\x93\xd7\x8bf\xa1\xff\xbb\
-\x1a\xca\xf7\xc7\xe3\x81\xae\xf0\xdd\xc7\xebE\x05\xbafo\
-\x16K\x0b\xdc\xe6\xb4\xf5\xbf\xb7\xe7\xad\xd2\xf1\x7f\xdc\x9d\
-_\x5c\xfck\x13\xf2\xec\xe8\xf8\xa1\x9f\xc7\xab\x8e6\xa0\
-\xed\x8e\xe3\xa8;\xf7\xc3\x1c\xf6\x1e\x0c\xa1)\xe5\xac\xf1\
-[\xd1u\xf6\xde\x9f_\x9e]\xbd\x9f\xdf\x9b\xa1G>\
-\xdb^\xe2\xden)c\xb3\xc4u\xed\xde\xed\x9b\x93Z\
-\xea\x87g\xbc\xed\xe0Uu\x8c:\x9ef\xa0\xb8:\xfe\
-\xfa\xdd\xf9\xd9\xe2\xee\xeabqsr\xd9H\xa0\xb5C\
-7U\xd4\xd6#W/\xff{qz\xb7\xfd\xd8\xcb\xab\
-\x9b\xb3\xc5\xcd\x83$\xda8pzuqu\xf3\xc3\xb3\
-\xdf\xfb\xb0\xad\x0e\xb5\xbe\xdd\x1fx5l\xcfFsy\
-yr\xbbX\xed\xde\xbe\xb9z_{U\xc1\xbb\x9bw\
-\x8b\xcd\x11\xfe|u\xf5\xb6\x0d\xcd%\xd1D\x1e\x11x\
-\xfa\xe1\x87gs\x12\x04\x16\x11\x7ft\xb4u\x96\x02\x9c\
-)?\xc5}m\x00?q\xa8\xd6V{\xdc\xe8\xbb\x9b\
-\x9b\x1a\xf4\xabW}\x5c\xdc\x8c\x01e\x1c\xcd@\xff\xed\
-\xf6\xf1\x0c\xc7\xe6/_^}X\x1d_\x99\xd9X\xa0\
-Rqo\xce\xd5J\xab\x1e\xaa_W\xac5\xf4@_\
-\x03X\x99\x1f\xc0\x9f\xceo\xcf\xab\xd3\x8f2\x87\xadF\
-\x8b\x0a\x9em\xa0-\x92\xd6\xacY;\xc0\xe0u\xbb\xfe\
-\xb0y\xe8\xe3\x96C\x8b\xb7\xd7\xab\xa3\xf5`\xf3\x97\xc1\
-\x1f\x1e\xbb\xc0\x80\x9f-^\xdd\x8e\xcan{\xec\x98\x8f\
-\xc6z]c\xeb\xf5\xe2\xb4\xa5\xc7\x95\x981\xb8.\xc7\
-\xde\x17\x95\x91\x851>_\xffW\xd3\xe0\xd1\x8b#\xd7\
-\xfa?\xdaZ\xe2\xe3\xb2\x04!\xb6\x7fpk\x99\x9f\x87\
-<\xb1\xad\x9d\xbe\x0b\xf3\xab\x9b\xf3\xd7\xe75\x88\x0f\xe5\
-tI\x94G\xab\xd3\xe9hmpZ\x1e\x02\xcc\xf75\
-\x87.Nn\xfe\xe5\xe6\xe4\xec\xbc\x1a\xd1z\x85\xfe\x88\
-h\xad\xf5\x10\x94n\xef\xae\xae\xdb\xef\xb1tCDm\
-\x94Y\xb9\xbb\xfbx\xb1X\x1e\x99\x0f\x9e\xf7\xe2\xf78\
-l\xdf\x0d\xd0\xca}_\xacW\xb9z\xf5\xeavQC\
-\x13\xd6\x0eN\x0b\x93\xcf\x17\x86[\x84\xd1\xc8\xc6q?\
-\xe8\xcf\xe5\x88\x8bMr\xc4%\x9e\xee\xb6\xcb\xa2\xbcz\
-u\x18\x8e\xb8\x94'\x85\xad\x22\xe1W\xe5\xc8q\x9a#\
-\xe7\xe9n\x1f\x8c#\xd7\xdf\x1cG\xc8\xd3\x1c\xe1D\xb7\
-O\xcf\x16\x8b\x83q\x84\xfe\xb4\xb03^\xe4\xe2\xec\x00\
-\x1c\xd5\x93\xca\xbb\xc5\xcd}\xc5\x96M\x11\x08\x19\x03\xc9\
-V\xed\x8d\xe7\xd5\xc0\xa8\xa48\xc6\x81\x8f\xcb\xf2\xac\xc5\
-\x1c\xe9\x1e\x1eO\xbc\x81\xb5\x14\xe2.0.%\x8ad\
-\x8c\x9c\xbfZ\xfc\xcb\xc9\xbb\xdb\xdb\xf3\x93\xcb\xffs\xf1\
-\xae\xf5f3\xf8\xd6a_,Nk\x93'\x17\xefO\
->\xdev\xe4\x9c\xfdy\xf1\xd3\xf9\xc9\xdd\xfdY\xba\xba\
-\x99\x17z\xd6\xd3\xdaK\x10\xc9\xb2\xc6\xcc\xb2K\x9fi\
-5\xae\xa8SV\xe3:\xa5HLZ\xc8\xe2 V\xe3\
-\x8a\xf9\xb40\xc98[\xe8\x84\xb0Cz\x96\xd7m\x92\
-#\xf7\x89n\x97W\xa7\xf4\x8a\x0f\xe3Y\x94\x13Y\xcc\
-2\x16/m\x07a`;\xa8\xc4\x03'\xf4\x7f\xca'\
-\x96\xdb\xc4\xed\xef\xc8\xbd\xa3\xd1\x17r4scK\xce\
-\xa7\x1d\x8d>\xd7\xd1>\xd0\x0f\xcfB \x94]r\x0c\
-4\x15%\x03\x117\xd5\x07\xf4\x03\xd7\xb2\x09E\x8aH\
-\x19\xcbV\x94\x1c\xc20lD\x1f\x1b\xa7\xa9\x8c\xca\x19\
-&7^\xbc\xb9Y\xbc\xaa\xd7+\x8fR\xe8X\xee\xf5\
-\x0a\xfc\xeb\xe5\xf9]=\xc7\x7fw\xbb\xb8\xf9\x8f65\
-\xf1\x7f/\xffz\xbb~\x8e]\xa7}\xce\xfemq\xf7\
-\xe6\xaa\x8a\xad\x8d6N+\x0f\xd3#W\x08\xebG\xad\
-\xc0a\x99\x07\x1c5\xef6\xeab_k\xd4\x14\x05(\
-\x98\xb5\x1f9\x0b\x84\xa5\xf7#\xa7\x10(\x89A\xdd\xc8\
-\xdd@5\x89\xf8\xe9\x91\xfb\xc1G\xde\x97\xfaK\xbdv\
-\xbem\xb3\x14\xf5\x9a\xab\xfd\xbc\xa8\x13\x8f\x7f(1\xc3\
-\xe7;\xd1P\x1c\xd4S\xbd\xa3\xc1\x05H\xd2\xc8:\x1a\
-\x8c\x81)\xd5\xb3\xa7\xc1\x81Y\xd5\xe2\x09\x1a\xb8\x98\x1c\
-\xca\xec\xa7i\xa8\xf357\xe7\x1f\xfe@\x80\xec\xc5\xd1\
-gX\xff\x8c{sF`\xd4\x882\x9b\x13\xa4\x98\x87\
-\xf9Nde,\xb9\xeac\xc4\x1cA\x9c4\xd9\xbc\xb7\
-\x1ar\x08J\x8d\xde_\xd0A9\xcc\x9f\xa6\xcb\xff\x0e\
-\xe8\xd2\x80\xe2\xa9\xc1\xbd\x8b\xf9\xd2\xb6\xa2#K\x0b0\
-\xf5e+\x9a6pe\xe5i\xb2\xcand!\x7f\x15\
-\xb2\x0c\xeb&\x8d,/\xa2,\xb4FVk\xf0\xe4b\
-\x93\xac6\xa3DkCosH1Z\xc0Mu\xbd\
-q\xefU+\x9c\x09\x99\x142\xa2\xb5\x0a1\x81*\x93\
-tl\xf5\x22\xb9\xf8N\x9e\xe8u;\x18[\xf3Gt\
-\xa1\x9b\xfb\x8c\x99A\xc2)*Y\x0c\xea^<w\x22\
-kN\x0e\xee\xa9\x99\x1dg\xe9\x90M\x8e\xadS\xe78\
-\x92\xd4U\x1d\xe1\xae\xea\x93\xdc\xe5N\x96\xa6Z\x0e\xc7\
-\x1d\x02[\xbac%\x09\xc1\x98XC\xdb\xcf\xe4PQ\
-\x9d!(\xa1#\xd1\x8c\xd4\x81\xa5\xa8\xcd\x0c\x01\xcd\xac\
-\xd8\x8e9@\xc1\x1e\xa5\xc1\x82\x9e\xd2\x074T`\xeb\
-\x1c\xd4\x80\x9a\x98\xe4'\x1d4h'\x93S\xd4\x03\x9a\
-\xdc`j\x08\xe9\x84\xea2cJ\x88\xe6\x94*N\xe9\
-1\xc9\xcc\x10\xac\xa3\x0f\xe9s\x16\xef\x89B\x1d\x0b\xd0\
-X`:C\xe3l\x9eM]\x9c\xa2\xcfw\x1b\xf6\x13\
-\x1c\x0b\xeeh\x9a\xc8U\x17\x13'\xe0\x13\x1e\xd8\x9cJ\
-\x0c\x948K\xe9\x9c(\x1c\x0a\x9a\x17\xe9=\xae\x00\xc9\
-\x90A:gu}\xd6\xb94\xe3n\xc4\xcd\x89\x0b4\
-)\xd5\x0b\x18,\x8d\x8b\xe8b\xee\xfb\x90\xd8\x8fOp\
-\xb7L\xc2\xa5\xe0g\x90xzq~\xfd\xffN\xee\xde\
-\xac\x0b\xbe\xc7\x04mt\xa8{pk\xbf\xc7\xeb\xa9\xeb\
-\xb1\xad\xf1\xfa\xee\xe1:\xee\xbbz\xbds\xf1\xa2\xde{\
-\xfa\xc3\xef\x1f\x8f\xee\xf9pt>\x16\xbe\xbd\xbb\xb9\xfa\
-\xdb\xe2\xc5e\xbd\x7f\xbd\xfa\xbd\xbc1\xf4\x02\x81$\xb4\
-\xd4\xed\x1eo\x1c\xd4\x81\xbe\xb8\xb9zwy\xb6\x0e\xfe\
-\xf7\xd5\xf9e\x8f\xd6\x9b]\x8b\x9b\x8b\xf3\xfa\xcf\x0b\xbd\
-\xc7\xceN\xea-\xa5\x9b\x9b\x93\x8f\x9d\xb0\x86\x0e\x97\x9b\
-\xb5$\x90\xad\xe0\xadW\xa5\x95\xb5\x7f;\x9a\x13\x13p\
-b\x99q\x013t\xe5\xa3?5\x94\xc1\xdc\x9cg\x9c\
-\xc0n\x85\x1b\xa6\xe0\xe2\x16\x1dfP\x98x\xbd\xfa\x8f\
-\x15\xd6{\x8b2\x06O\xe7\xb2\x84\x83\x81\x0a\xdb\xa6\xb0\
-\x10\xd0\x08\xa1\xf5\x86\xc3\xc04\xd9;\xcc!\x85Kn\
-\x08K\x01C\x97\x9980K\xf1e\xa3\xa9\x10\x85\x90\
-g\x12`\x98\x9e\xd2\x81\x05,\x8asY\xab\xaf\x08\xe9\
-*64\xea\x08\x12\xe86s\xed\x84d\x00\x89\xb9\xf5\
-22A\x19%h\x1d,\x08ZH(\xd6\xaa\x17\x82\
-\x08G\xc9\xd6\xe88\xa0\x92\xa0Z\xc4\xb25;\x8e\xbd\
-\x14\x08Q\xcc5\x8eFl\xa4s\xac\xde\x93\x1f\x06B\
-\x12\xd8\xe0QU\x9d\xb0Q\xabc\xc3\xa3\xf6Gl\xb4\
-\x93^\x16)8\x86\xe58\xb0\xa1Q\x12\x10\xe6\xf4\x91\
-\x83updkl`$\xb65+\x01\xa1\xc2R\xd9\
-\xef\xc4\x8c:\xea\xa4\x8c\xda\x1c\xc1Q\xef\xeb\xf5G\x1b\
-\xf9q\xab\xed\xff\xbc1\x13r\xbd\x8c)\xb16\xffq\
-\x1fU~\xcb!\x9d\x99@E\xedK\x84t\xf9\xea!\
-]\xcb\xde!}S\x91\x8f\x03 \x93\x80[Z\x1f\x93\
-\x98\x14\x8a\x0a\xaf\x07@\xa6\x00$\xa5\xe8\xb0\x04.\x99\
-\x1b\x01\x90u\xc5\x7f\x1f\x00\xd9\x15,\x90\xca\x8607\
-H\xd3B\xeb\x0d{@aK\xef\xb0\x02Lh\xb9!\
-,\x0c2\xa5\xf4\x01\x90#\x80<}=\x00\x8e\xe0\xe8\
-2c\xfd.\x00\xb21\x84&\xb7\x00\xd8\x09\xb9\xf7\xd3\
-^\xc6\xe8\xd2#8:\xffX\xbd\x0b\x80\xe3\x80\xba\x98\
-4\x8e}\x8c?#G#6\xd29V\xef\xc8\xef\x02\
-\xe0\xa8\xaaN\xd8\xa8\xd5\xb1\xe1Q\xfb#6\xdaI/\
-\x0b\x1dJ\x1am\x04@F\x83@\xd4.\x00\x8e\xe0\xc8\
-\xd6\xd8@\x17\x00Y\x10\x881[\x00\xec\xc4\x8c:\xea\
-\xa4\x8c\xda\x1c\xc1Q\xefc\xfd.\x00\x8ec\xea\x02\xe0\
-~\xa7B\xf2?\xeeT\xe8\xd3!\xbd\x0fe_\xfa\xea\
-c\xff\x0b\xa3'\xaf_8\xfe\xf1\xae_\x0a\x01R!\
-\xe4C$:\xca]\x13\xdd\xdf\x0f\x81\x99\x87$\xd0\xff\
-\xfe\x09\xecO\xb7\x0eL \x96\x7f<\x0b,zH\x02\
-\xe3\x1f\xd0\x02\xed\x90\x04\xd2\xae\x04~K\x22['\xb8\
-\xcbA\x93\xc8?\xe4%'\x97\xc2\xbb\x92\xf8m*\xf6\
-\x93$\xe6\x97\xb7\xc4\x03\xdeo\x9f+B\x98&\xcb&\
-\x13_KS\xdbI\xd4\xafi\x89*\xa0\xa1\xe1\xdc\x8d\
-\x8f\xd0\x80C\x95\xbb\xf1\xb9C&%Z7\xbc$\x10\
-\xb6\x08\xebF\xe9:\xf1\xb8\xc7\xf4\xed \x84 \x16\xcd\
-v\xe3\x8c\xd8\xd1\x92f\x08$j\xc1Z\x7f\x85\xa3:\
-\xc5,@\xdd\x8c\xd1f\x8c@\xa1$\x87\x08\xabR\xbe\
-\xe9\xe1\xf3\xf40'D0Q\xcdC*B\x88\xf2k\
-\xcf\x06\x12\xe9An\xf0\xf4s\x19\xfd\x98v\x9f\xcb \
-\x07-\x86\x88\xa9\xbf\xad\xfb:^\x00\x8b\x84\xcd\xd8\xc0\
-\xa5\xe0r\xa61\x08XRK\x19\xe0\x82%\xb3\x82\x02\
-\x1c\xe9<c\x07\x0b7\xb1\x8a)D\x12\xd7\xea\x09\x84\
-\x11e\xa8^\x08\x02\xadH\xce\xd4\x00\x855l\x04\xcb\
-,\x18B\xcd\xb1\xac\xd5\xcf\x02\x1e\xc8\xc5[}\x0bH\
-s\x0b\x9e\x11:X\xd1R\x8b\x0a\x02\xa9\xa8\x94\x07\xb0\
-\xf6\x89\x04\x982\xfa\xfa\xb2\x14\xf4 'W\x08?t\
-\xc7\xc7\x9a}\xcf\x9b\x9e\xd4\xc9u\xc6\x0a\x99\x051\xda\
-\xf4\x17\xb89\x935\xb0\x109g\x05\x15\xeek?\xd0\
-\xc69\x90\x996\x13\x02qW\xf3\x01$d%\x9d\xc9\
-\x927\x8c\x87\xdaR \x8a\xf1J\xb6\x02;\x91\xe8\xcc\
-\x10\x14\x0b\xb9\x8d \xcd<*\x88\xe4\xa3\xecH@R\
-\xd4\x8131\xd0\xac\xdbpm\xe9\x1c\x85\xablc0\
-\x22\x92{\x8c*\xe6\x02\xc4\x1b\x95C $3\xca\x83\
-\x94\x18\xc1|\xe8O\xdc\xd7\xee;\xee\x08^\xc8\x0a\xcd\
-$@\xd9\xa3P\x15]\xa08\x15\xe3\x99\x08D)\x82\
-\xad6\x01\xe7P\x1f\x9b\xba\xee\xeb38\xa2\xb5\x98\x13\
-`J\x1c^\xc1fx\x85$\x9a\x09\x9a!\x9bn\xb5\
-\xd6\x9f\x8f\xaa\x15\xab\x0e\xbdb\x07\xb1{Uj\x02\x9b\
-&G\x83[\xafHj\xaf\x08\xcc(\xb2\x82\x05\x92I\
-\xdd\x96`\xebe1\xb26U\xbeB\xdc\xee\x91?-\
-\x11I6\x9ey\x82\x9b\x0bQ\x05\x11\x88B\x93fA\
-@I\xa1Z\xe5\xc6\xca\xa4\x83\xc1\xf4\x9e#5P5\
-\xe4Y\x08\x14\xcc\x94\xac\x18\x83\x99\x96|\x00[m\x5c\
-\x9ae_[\x022\xd9(\x1e\x04q\x05\x1d\xd4\x9b\xf8\
-\xf5.\x89w=\xffq\x85\x88\x8cc\x19*\x86ZJ\
-3\xd3\xc2\xaa\x1c\x83\x08N\x16j\xc4\x94\xb0T\xabX\
-B\xac|d}(\x08dF\x85\x9b\xba\x884Vc\
-\xc1\x92\x88>(\x81\x15\x8d\x1e\xabe\xfbm3\x22\xdf\
-2\xc7\xfa\x0f\x91lK\x80\xbb'\x1d8\xd9\xf2WO\
-\xb6\x98\x07\xba\xf5F\x84\x8fr\x14\xb9\x03\xb3c\xf6I\
-\x8a<A\x02\x93\xd7\x93\x14\x05\x82\x12\x16[\xcfR\x14\
-\x04\x85\xc4r#\xd8gBJ\xb2\x8fij\x1d\x1c\xd3\
-\xd4\xd8@\x9f\xa7\xc8\x14JfYOS\xc4\x01\x1c\x16\
-\xde\xa5)B\x10#\xdc\xa8_\x04\x94]J\x8c\xa9\xea\
-\x1eT\x8c1[\x8d\x0dl\x8e\x80\x04,R\xcbz\xba\
-\x22J\x88L\xd3\xf5tE\xcc\x80\x18\x22}\xc6\x22\xb6\
-F-\xd1\x98\xb1V\xa0ht\x19kl\xa0OZD\
- E\xd4\xc7\xa4\xb5\x0e\x8eIkl\xa0O=$\x0c\
-\xce\xc4\xb4\x9e\xb7H\x0b\xb8\x8a\xfaz\xe2\x22G`{\
-\xdc@ d\x10\x8f\xa9k\xc4\xc6\xcc5V\xdf\x1c\x80\
-\x05$K\xe11y-A,\xca\xb9\x9e\xbc\xc8\x12\x94\
-\xc4\xb2\xcf^d\x05B8c={\x913\xa4\x90\xfa\
-\x98\xbd:;\xee\xd3\x17)-\xbb\xd6g0R\x03\xc9\
- [\xcf`\xa4\x09\x9eJ4f\xb0\x15(,\xd2\xa5\
-\xb1\x11\xees\xd9\x00\x07Z\x978H\x03XK\x9f\xcb\
-Hui\xf7}:\x22e\xb0\x08\xb1\xf5lFR\xc0\
-3\x84\xeeAmX\xac\xcc\xb6\xaf/\xd6\x14\x98\xba\x9e\
-\xceH\xa4\xb9\x0bF\xd7+\x91G#\xf8q\x0d\xee\x13\
-\xdb\x00\xa3\x17ZOl$\x0aJ\xea:f\xb6e\x0f\
-r\xe5O]\xc7\x028\xc3\xba\xd4\xd6\x06\xc6\x82\x22c\
-j\xebT\xd6e\xb7\xdd\xaf\x1e\xf8\x7f\xde\xd5\xc3\x964\
-\xfd\xed\x9ax\xffIs<d\x9a\x9ez5\x8c\x93&\
-\x9b\x99xwl\xfb[_\x9c\xf2\xc4\x9bc\xc2\x19\x9c\
-\x91\xad\xc8\x84\xf4]\xdf\x1d\x1b\xef\x863\x01\x0aq\xff\
-\xb6\x8c\x10H\xb8G\xf6o\xd6 \xb8k\x1aww\xc7\
-\x0bCVPt\xc7g\x87\x81E\x98\xb9\xcc\x08\x0a\x19\
-\x16\xa5\x03<B\xccl\xbb=\xa6\xad\xbe\x8b!L\xb2\
-\xa6\x0e\xcc\x99V:\xda\xacT\xd4\x12\xa3\xa3- K\
-\x08St\xb4\x8dew\xa5\xcdY\xbc\xd2v\x10\xba\xb0\
-|U\xba\x88\x02\x84\xc5s\x07\xba\x18\x81S2h\x82\
-\xae}\x07\xefn\xb1\xd3\xe0\x9dv\x0c\x1a\xfb?\xc8B\
-\xe0FN\x5c\xaaN\x7f\xbbt\xd9\xc1\xe8\x9a\x8e\xb1\xae\
-\x96_$\xc6\xba:>\x11c9U\x952\xf6\x8a\xb1\
-\xdb\xf3\xf7\xf4{XQ\x8c\x90\x96o{\x8c{\xf3\x02\
-\x16\xe2\xe4^\x7f\x0a\x14\x09cy>\x91\xaawU\xf3\
-xR\xc1`V4\xbd?\xa9\xa0\x04R\x93\xec_\xd9\
-b@\xc50\x19O\x1f\xb6\x96=\xed\xca~:o\x17\
-7\xda\xc5\xa6\x8a\xab\xfcb\x17l\xe2\x1f7;\xf5\x96\
-}q\xb5mo\xb1O-\xc5\xb1e\xfd\x98\xefj\x0f\
-\xa7\xa5\xc5\x16i\xf4\xb44\xe7m\xd2\x0e\xb5\x16\x01[\
-\xe4\x14Kl\x89\x9f\xcfR\xc4~,\xb1%\x7f>K\
-\xa7\xf4%YrU\x9f^\xd5Bs\x1f[j\xdb\xe7\
-\xb3\xe4j8\xc1\xd2\x8e\xd2\xf0\x10,\xed\x9e\x1c&i\
-t\xe2}h|\xf9*q\x0f\x1a\x9dt\x82\xc6Ii\
-\x87\xa7Qh\x9a%\x91=\x5c\x12%p/\x96\xc4>\
-\x9f\xa5\x97\xafl\x81_\x90\xa5\xe9\xf0\xee{\x86w7\
-\xb7}X\xd2\xd8\xc7\x96\xce\xaa5})\x96\xd8\x1c{\
-\x96&:c\xe5\xb1\x81LP8\x06n\xe7\x8e\xa5)\
-iy\x86\xb8\x934\xda.M\x0fgK\xa1\xd3\xb6\x14\
-\xfe\xf9\xb6\xf4r\xcfS\x05\xf7\xc8}l\x89\xea\xf6\xa5\
-lIXbzA0)\xfbx\xdc\xe2e\xbe\xfc|\
-\x96\x84\x95~kI\x90K\xc1)\x96j\x99=r\xdc\
-\xe9\xb0\xed\xc8R/m\x9f\x1cG\xed\xcf\x97:\xa1\x12\
-d\x9a\xb4%\xe4=r\x1c\xe2.\x1e\xf7\xd9M \x90\
-\xb9\xb8\xb8~\xf7\x89e\xaf\xb6\x0e\xa0\xec`\xc4(\xb4\
-\xb5Igv\xa5\xca\xd3\x1e\x9d\xf5\x0c\x0e\x0e\xd9\xc5\x89\
-\x90'\x92\xfb\xeeb\xc5\x87?1e'\xdbW;\xdd\
-\xbeN(\x9b\xca\xde\xeb\x8eN\xafg:\xbd.\xea\xf4\
-\xea\xaa;\xae\xd3:q\x0d;\xb5\xdc\xd8\xf4$\xde\x13\
-Q\xc9\x83>o\xf6\xa0\x9f`\xea\x97\x13\x12\x82 \x0e\
-\xf5\xa9\x99\xab\x8a\x96\x04\xf2\xa0\xb0\x9d\xd6\xac!W\xb3\
-\x90\x875k\x8a\x13\xc5L\x1c0\x8bV|N\x90a\
-%\xb0<\xffU\xd9\xcc8\xe4ZX)\xa0\xc4e\x86\
-\xe0\x8ai61\x0d\xd4\xa9\x88\x09\xb0h)\xda\xa9\xa8\
-\xa2\x84T\xd1NCd@YH\xa4\xd3\x10\x07 F\
-\x9an>\xb8yPF\xeb\xf6\xd4\x03\xa8^\xf0\x90\x0b\
-\xd2\xb8y\x88\xd8\xca\x8e\x98\x95\x0b\xc6\x8c$\xc1]\xb2\
-\xcc\xe6\xa2@\x89Q>E\xf5\xf5\xc9Y7\xe1\xa5\x0c\
-\x81(\xc6\xfd\xe4\x18\x0aXb\xf7`\xf4XtD\xbb\
-\xa2[f\xe7\xbe\xac-\xa3>i\xcb\xc5\xf7\x88\x0cR\
- \x94\xca\xe6;\x95$`\x9a\xd2\xdd0\xd9V\xb6\xa2\
-s\x83\xc2b\x9c\xb1\x9b\x93\xa8\x83\xcf\x18\xc8\x16s\xfe\
-\xa2\xce/\x5c\xec)\xc2\x02e\x0f\xc2\xe6\x8eP\xd4\xd8\
-\xa8g\x0c\x0dR\xd0zG\x9d[\x01%c\xb5\x8e2\
-5p!\xc6\xf85c_\xa0\xed8\xfc\xfdoy}\
-\xa0\xc9\xdbl\x13\xa9\xa7\xbb}\xf7\xeb\xd2u\xa8T1\
-}c\xb5\xd1Fd\xf0\xf8\xa6n\x10`j\xc1\x9c\xb8\
-\x01\xdc\xdd+\xfeUY+\x87eM\x89\x0b\x0a\xb7\x14\
-KEL\xf3\x8b\xe5X\x81\xe2\x84\xdaS\x9a\xc0bE\
-\x7f]\xc7%\xfa\xc6\xe9\xc19\x95\xdf\x10\xa7V\x00\xc9\
-\xbd\xc4\xe6\x0a\xc1\x8e\x8aB\x1d\xa7.\xa0\xa6\x86}R\
-&\x02\xb1B\xfa\x84\xf3O\x9d}m.k7\xcf\xec\
-\x16\xb5\xdb\x89\xae\x03\x9c\xd8\xa8\xb0N\xac\x048.\x19\
-8\xb5\xb6`C\x8bB\xa3e\xcf\xfb\xc0[\x17I\xdc\
-\xb6F\xe2\x9c\x0c\xac_#\xf1\x80\xa4\x89jy\xe2<\
-\x5c\x85ib\xd5\xc9~\x89\xca~\x1d\xcb\x89\xb5.O\
-\xbb\xaaO\x98\xd8\x84\xbdO\xfa\x11WB\x0fI\x1a;\
->ii\x94\x13+Nw\xabSO\xac\xdf\xdd\xad\xf5\
-=ep\xd3~X\x12I\xb1\xac\xfc\x10A\x0b\x06\x1d\
-\x8a\x9c\xe9+;\x15\xd2\xce\xa2\x8aA\xa0\x11\xd2\xc6z\
-\xb1\x08\x22\xa4\xfa\x895eO\xb7\xd6<\xedj\xfe\x92\
-\xa7t\x18\x0fl1\xc8O[\x0cn.#\xecAI\
-}\xde\xcb\x84\x10\xd1\xf2hubS\xce\xde`\xd2\xc1\
-4(\x7f\x19\x09\x04\xc9\xee\x143\x01\xd1t\xe1\xfc\x9a\
-^\xb4q\xfa\xee\x04\x94\x8e\xee='\x0clE\xc9\xbe\
-\x16)\xf3\x82P\xac\x98\xcd\xe6\xd1~\x09\x17\xf9\xaa\xac\
-ho)\x01\xa4\x18E:V\x86\xe4\x84a\x1b\xac\x98\
-B\xbaYt\xac\xb0\xe4r@\xbf\x88\x96\x12\x87s\x98\
-\xe9\x8bn\x11\xf6\x89\xa5\xed\xbbe\xf0'\x96\xcc\xef\x96\
-\xd7\xdf+\x0f}\xcd\x91\xf3\xbe\xc9\xa5\xffLB\xff9\
-\x85\xe9\x87\xf4\xd8Y\xf7y\x06\x8f\x9d}\xfa\x0b\x19\x87\
-~\xcey\xfb\xdc\x16m{l\xa7\xbf\xcf\xb2\xf7WV\
-\xfa\x9bl>\x84\x99)a`\xfb\x7fg\xa5\x17\xc78\
--\x8ev\xfc\xca\xca\xb40>\xd8\xedQ'\xdc_%\
-\xfd\xc7\x81\xa6U\xc2{s\xd4\x7f\x1ch'a\xba\xef\
-\xc7h\xd8\xd1\xa7\xbf\x12\xd5\x7fUj\xfa+T\xfdW\
-\xab\xf6sd\xcc\x1d\xbe)\xf5U\x1c\x19\xf7\xb7\x9a\xfe\
-Cd\xd3\x8a\xc4\x9d\xacf\xff\x0f\x91\xf5\xc2\xf4`\x9e\
-eE\x7f!G\xaf\xea\xb6\x13GV|\x0f\x8e\xa6\x85\
-\xe1vay8\x8e2\x7f!G.\x8b\xb2#G\xf8\
-59\xe2\x03r\xc4\xbf4B\x0f\xdb.\x1c\xa5\xee\xc1\
-\xd1\xb40\xdc.\xcc\x0f\xf8X\x82\xe6\xdf\xd1C\x09\x8d\
-\x90\xf6A\xda\xfak\xf5\xbe\xf9\xf8R\xb9\x04h\x12\xdb\
-\x8c\x18\xc8M\xd5\xeb{\xa5\x84\x06\xa4\x89>s\x02\xd2\
-\x88\xd4\xa3?U\xd4\x81\x84\xb4\x81i\x82\xc6\x03\x143\
-g\xc8\x92\xa8~\xbf\xdfJ\xaf~\x1a\x10R1]\xab\
-\xed@\xeaEs]\x8cC\x1a35\xe1\xe2\x10\xc3\xda\
-\x16D\x06\xc9&T[\x13\x067t\xa9`\x82\x9a\xc5\
-\x11;\xc4\xb0\x97\x9c\xca\xf7\xbbR\x1bX\xfe4(\xc3\
-V+/\x01\x06\xc2L\x97#\x11\x08F\xe3Y\x01U\
-\x0f\xb4\xdc\xc2B{\x89\xb5{#\x9f\x87\xe9\xb0\xed\xef\
-\xb4>\xfe\xde\xc8\xe6;\xad\xcb\xdd\x9bw\x17\x8b\x17\x8b\
-\x9f\x16\x97Wgg\xebo\xb9V-}\xd3\xcd/\xd0\
-\x8d\x98p\xaf\x9b\xf1\xa1%6\xf5$\xd7O.\xc6\xcc\
-\xc5\xf3 \xea\x0a\x86F\x0c\xa0\xb3\xd5\x91\x05\x812\x17\
-\xe2\x86\x11G\xe4Q H:\x96\xd2 \x95\xc2\xe9G\
-^Z-\xae\xdc\x04A6j\x0b8[\xddO\x9c\x91\
-\x83z\xc6\xc3^m\xb6\xfd+\x80mH\xb5A\x07t\
-\xc2\xa8\x0d\x22\xa4\xba{\xdf\x8b\x1f\xbb\xdd\x07\xde\xee\xb6\
-=T\x91B\x85\xa2\x0c\xf3\x8a\xe3^Q #,:\
-c\x10\x13J\xe3\xe7\x9b\xecs\xf0n\x9ea*\xf8y\
-T\x7f\xb7<\xa1\x5c66~E\xf5\xf9\xaf\xac\x02P\
-TEn&\x19E$*\xed\x01\x5cH]f\x05\x8a\
-\x17+Y\xf6WEh\xbaR\x0e\xaa\xa8\xbb\x05\x91J\
-\xce\xd2!-B\xb5\x8auH\x14\x8bG\xaa\x90B\x9f\
-r\x84@%*\x19\xdf=\xa1\x1d>\x90v~\xd7\xe7\
-\xa6Zo\xd1\xf2S\x9dA9]n\x9f\x8ax\x06E\
-\x08\xb9\xb4\x18\x91\xc4Tt\x08y\x04\x81\xec\xa5E3\
-,\x5c\xdc\x86 &@li3\x170rb\xaa\xd8\
-*\xdc\xcd\x5c!\x5c9c\xa8\x9d\x18Yk\x1b\xa4\xa9\
-J\xb6H\x16`,\xadM\x22\x84\xe2:hV\x04\x94\
-L9*\xaaCH,G\x5c@0,u\xc0\x04Q\
-m\xc4\xd6j\xff\xb8\x8e\x06\x94BDC\x84\x1bQ\x03\
-\xf2\x12\xc6-d\x9a\x9aZ4_N\x0b\x13\xde>\xf6\
-m\xe8\xe3\xf0\xa7\xa1\xbd\xd6\x9f\x88ur\x90X\xc7\x91\
-`\x86\xaa3&P\xd7\xa1\xaf\xdc8C\xd3\x98\x85@\
-\xa2\x17\x1b\xc6O\x0cA\xc5+j\xa0\xe4\x864`E\
-\xc9f\xe1\x90\x9c$1TF\x14\x5c\xaej\xe2\x84N\
-\xad\xc9h\xd9\xa1\x00F\xba\xb7\xc6\x92*e\x0c\xee\x98\
-u\xc7\x86\x9d4\xca2\xec\x8dE\x7f\x1c\xf6Y\xa0p\
-a\xe1V\xb5\xed#\x84\xa4X+M\x90\x1a$\xcd\xd9\
-\xd9\x94S\xb6\x0ej\x0b8\xfa\xee\xd4\x87\xe6\x102\x95\
-J\xe1\x990\x83\xa2\xb1\xcd\xe6\x02\xe4\x81\x99\xf6\xfc\xb1\
-\x1a\xe9\xb1\x1a\xd7\x17\xa6\xf8\x84\xd7\xfa\xf3\x8de2\x00\
-#\x02K|\xd1\x0f\x06\xf4\x16\xb4\x19\x06\xe8\xd3AZ\
-\x18\xc4\x5c\xa2R\xaf\xcd[\x15\xb3\xb9\x1e\x82%1W\
-\xd4\x00M\x1cc\xddu\x1c\x98\xac\x88m8Y\x14.\
-\x9d\xe7\xa9\x80\x16N\xe5\x0eu\x87b\xac!U\x90\x09\
-\x18\x12F6\x94\x22\xbc\x96\x0d\x03'v\xd1\x16a\xb8\
-8\x16;*\x02\xe2\xca63\x07\x16\xb1\xe0\x95;R\
-\xba\x0e\xbd\x8c\xe2\xcb\x93\x18Qp-h\xdaPt\x1d\
-\xe2\x08\x93\xba\x0eCD\xe3,[\x87\xfd\xe3Vt\xd3\
-\xbf\x99\x85w=\xf5\xb4r\x10\xff\xee\xbb\xe5.\xcb\xf0\
-H\xa0V\xdc\x07\xb4\xa8\x06Y\xd3[\x90\x09S\x1b;\
-gA\x1b0\x0a\xc5\x94\x86%\x17,\xbc\x0c\x84\x85(\
-\xc4\x9a6\xb1`\x9a6\xcc\xc3E\x07L\xc2\x82\xaca\
-&m\xcc\x0d\x0b\x0eOY\xd66N]\xa1\xe2N\xb1\
-,iE\x06\xc8027*[\x89\xb0eeu%\
-\xd2\x86\x16!v\x1e0\xcc\xa1\x93\x01D\x9aKL\x82\
-\xc2K\xc3\x04M4V\x11\xdcK\x90\x0f(\x99k.\
-KJ\xf0\x00q`\xe4Fe\x09\xd5U\xdd\x8aR\xc3\
-\x8c\x0b\x97\xd2[pH\xf8\x06T4\xa8\xe4C\xe6\xd0\
-\xc2\x03j\x89.\x1b%=%t\xca%\xa8\x00\xa2\xb3\
-\xd1\xa6\xa3\xb08!\xafP)\x1e\xd1\xa1\x82\xa0\xce\x85\
-\xac5\x9b\x94\xc9+?MUod\x18hJ\xb27\
-sO\x0b'i\x98%K\xe6\xba\xa78T\xa8X\xeb\
-Ua`%$\x9e\x99Aj\xaaSm3\x12\xc4\xd0\
-\x9cf\x8ePP\x92\xf4\xc8\x11(\xd2\x88[*7J\
-B?Rjn\x8c\xe2\x83\xeb&\xb35\xcbp\x84\xd0\
-b*\xad\xa4\x17\xb7\xe5\xe9X\x11\x1b0\x02\xe1\x94\xb0\
-&[$8K\xf3hcV\xd4e\x8f\xc4\x8b\x8a\x0e\
-\xa8\xa9\x96\xaa\xf2\x86zI\x13i\xa8\xaa\x9a\x97\x16\x10\
-Z\xd78\x1b&\xaa\xc5}\x15$\x04\xa9\x8b\x12\x0d\x15\
-&\xcb\x01E\xd2hcw\x06\x0cE\xb5\x99(P:\
-\xd2\x93\x11%\x85)\xe8\xfe\xa4\x81\xa9\xb1\x1c\x19\x8c1\
-x\x1fFX\xc5\x18R\x22\x9c\xbbX\xdaP\xc7\x94\x18\
-\xd0,\x91<`\x91\x962`\xa1\x1a\x0d*HE\xbd\
-w\xf2e\xba.\xbcD\x991\x1bf\x82\x1a:`F\
-X|k\x88\xf8q\x1b\xba\xe5|\xc5w\x8fg\xfe-\
-\x9e}\x8bg\xdf\xe2\xd9\xb7x\xf6\x1b\x8eg\xc6\xbas\
-<\xdb\xe7\xfa\xeb\xfb\xe3\xdb\x9f^\xff\xf1w\xff\x1f\x87\
-I\xee\xb2\x11\x94\x00\x00\
-\x00\x00\x19\x91\
-\x1f\
-\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xed}mo\x1c9\x92\
-\xe6\xf7\xf9\x15:\xcf\x971\xae*\x14\xef\x11\xf4t\xcf\
-\x027\x83],\xd0\x8b;\xdc\xce\xe0>.d\xa9d\
-kG\x96\x04In\xdb\xf3\xeb\x97\x99%\x89E)[\
-Y\x96J\xee\xde\xeb.\xb7\xdb\x95O2\x18\x8c\x87\xc1\
-\x88L2\x8b\xf9\xdd?}\xfep\xba\xf7\xe3\xea\xf2\xea\
-\xe4\xfc\xec\xfbW\x04\xf8jouvx~tr\xf6\
-\xee\xfbW\x7f\xfb\xeb?/\xf3\xd5\xde\xd5\xf5\xc1\xd9\xd1\
-\xc1\xe9\xf9\xd9\xea\xfbWg\xe7\xaf\xfe\xe9O\xbf\xfb\xee\
-\x7f,\x97{\x7f\xbe\x5c\x1d\x5c\xaf\x8e\xf6>\x9d\x5c\xbf\
-\xdf\xfb\xd7\xb3\xbf_\x1d\x1e\x5c\xac\xf6\xfe\xf0\xfe\xfa\xfa\
-\xe2\xcd\xfe\xfe\xa7O\x9f\xe0\xe4\x06\x84\xf3\xcbw\xfb\xaf\
-\xf7\x96\xcb*y\xf5\xe3\xbb\xdf\xed\xed\xedU\xb5gW\
-o\x8e\x0e\xbf\x7fuS\xfe\xe2\xe3\xe5\xe9X\xee\xe8p\
-\x7fu\xba\xfa\xb0:\xbb\xbe\xda'\xa0\xfdW\xad\xf8a\
-+~8(?\xf9qux\xfe\xe1\xc3\xf9\xd9\xd5(\
-yv\xf5\xfb\x8d\xc2\x97G\xc7\xb5tk\xcc'\x19\x0b\
-Q)e\x1fy\x9fyYK,\xaf\xbe\x9c]\x1f|\
-^\xf6\xa2\xb5\x8dS\xa2\x8c\x88\xfb\xf5\x5c+\xb9]\xa9\
-7\x9fO+\x13?\xd9\x98\xf1\xec\xa6\xf6\xca\xfeE\xfd\
-{'p\x0b\xc0\xd5\xf9\xc7\xcb\xc3\xd5q\x95\x5c\xc1\xd9\
-\xeaz\xff/\x7f\xfd\xcb\xdd\xc9%\xc2\xd1\xf5\xd1F5\
-\xb7\xe4wz\xbb\x1e9;\xf8\xb0\xba\xba88\x5c]\
-\xed\xdf\xe2\x83|\xef\x0e\x15\xa8=|t\xfd\xbe\x1er\
-\x8e\x87\xefW'\xef\xde_\xb7\xe3\x93\xa3\xef_U\x83\
-\xd9\xd1\xc7\xe3\xdb&\xbd\xb9\xab\x08Ax<u\xabg\
-\xf3\x94\xde\x93::?\xac-\xab\xed~w\xbe\xbc\xb8\
-\x5c\xfdxr\xfe\xf1j\xf9\xe3\xc9\xea\x13T%\xff\xe8\
-\xab9\xffx}\xf1\xf1\xfa?V\x9f\xafWg\xeb\xfa\
-\xaaa\xcd\xca\xf5\xe9Q\xee\x0e\xec+X}\xbe8\xbf\
-\xbc^\x1e\x9f\x9c\xae\xd6J\xf7\xdf\x9f\x7fX\xed_\x9c\
-\x9cU+/\xcf\xeb\x97\xc3\xab\xfd\xf3\xcf_\xde\xad\xce\
-\xf6\xab\xc4\xe9\xc1\xdb\xd3\xd5\xfe\xc1\xe1u\xd5u\xb5\xff\
-\xa0\x81\x17g\xef&\xab\xff|tQ\xbb\xd3\x03l\xf2\
-\xf4\x97v\xfaO\xf5\xfcw\x1fV\xd7\x07G\x07\xd7\x07\
-\xf5\xfb\x0d\xbd\xb7\x88\xc6X\xa2\x96\xa9\xce\xfb\xe6\xff\xfe\
-\xe5\x9f\x87\xa3\xf1\xf8\xf0\xf0\xcd\xff;\xbf\xfc\xfbx8\
-~\x86\x02\x07o\xcf?\xd6\x8e\x1aen\xca\x1d\x1d\xbe\
-\xa9\x0e\xf4\xe1\xe0\xfaO'\x1f\x0e\xde\xad\x06O\xfd\x9f\
-\xd5a\xbe\xdbo'\xba\xc2\xd7_.V\x15\xe8\xaa\xbd\
-\x5c\xad=qj\xf0\xd6\xff>\x9c\x0cB\xfb\xff~}\
-rz\xfa\xaf\x83\x92W{\xfbw\xed\xdc\xbfih\x05\
-\xc6\xc3fG=\xb85s<\xbas\x88\xa1c\x8e\x06\
-~+\xba\xc9\xde\xa7\x93\xb3\xa3\xf3O\xcb[w\xf4\xc8\
-W\xd3%n\xfd\x972\xee\x97\xb8\xa8\xcd\xbbz\x7fP\
-K}\xff\x8a\xa7N\x9e\xd7\x01R\xed\x19\x1c\x15o\xce\
-\xbf\xfbxr\xb4\xba>?]]\x1e\x9c\x0d$\xd0\xc6\
-\xa9\xcb\xaaj\xf2\xcc\xf9\xdb\xff\x5c\x1d^O\x9f{{\
-~y\xb4\xba\xbc\xd3D\xf7N\x1c\x9e\x9f\x9e_~\xff\
-\xea\xf7>~nN\x0dm\xbb=q<~^5w\
-y{p\xb5\xba9\xbcz\x7f\xfe\xa9\xb6\xaa\x82\xd7\x97\
-\x1fW\xf7-\xfc\xc7\xf9\xf9\x87Aa\xa2z\x86\xdd?\
-}\xf8\xf9\xfbWKc\x08\xe7\xd0\xf2\xe0lmk\x09\
- \x8e\x92\xf1\x13\xd4\xd7\x0a\xf0'NUi5\x7fP\
-\xe9\xc7\xcb\xcb\x1a\xfb\x97\xa7\x07_V\x97-\xae\xdc\xb8\
-\xcb]\xb1\xc1\xa4[\xb7\xac\xdeV\xf9\xacc\xb4bC\
-uw4\x0c\x00+\xf3\x1d\xf8\xe3\xc9\xd5I\x1d\xc0\x8d\
-\x8b\xf1SG~\x05\x8f\xee\xa1Cd\xacY\xb0\x1a\xc0\
-0\xf0~\xf1\xf9\xfe\xa9/\x13\xa7V\x1f.n\xce\xd6\
-\x93\xd5\xef\xd7~\xfd\xd0\x95G\xfchu|\xd5:m\
-8b\xc7|`\xebE\x8d\x95\x17\xab\xc3!\xdd\xdd\xa8\
-i\xc1rm{_T\x1a\x0b-\xde^\xfc\xc7\xd0\x15\
-{o\xf6\x5c\xeb\xffh\xb2\xc4\x97u\x09B\x1c\xfe\xc1\
-\xc92\xff\x18\xe3\xfeT=}\x13\x96\xe7\x97'\xefN\
-j@\x1e\xcb\xe9\x9a(\x8f^\xa6Z\xbda\x9c\x96\xbb\
-@\xf1]\xcd\x89\xab\x83\xcb\x7f\xb9<8:\xa9\xde\xb0\
-)\xd0\x9f\x11\xadRw\xc1\xe5\xea\xfa\xfcb\xf8\xdeJ\
-\x0f\x88\xa85\x9d\x95\xbb\xeb/\xa7\xab\xf5\x99\xe58\x82\
-\xde\xfc\x1e\xc7\xcf\x1fG\xe8f\x18\xbe\xd9\x149?>\
-\xbeZ\xd5\x10\x83\xb5\x81\xf3\xca\xe4\xeb\x95\xe1\x842j\
-l\xec\xf7F\x7f-G\x5cl\x96#.\xf1x\xb3]\
-V\xe5\xf8x7\x1cq)\x8f+[G\xb4o\xca\x91\
-\xe3<G\xce\xf3\xcd\xde\x19G\xae\xbf8\x8e\x90\xe79\
-\xc2\x99f\x1f\x1e\xadV;\xe3\x08\xfdqeG\xbc\xca\
-\xd5\xd1\x0e8\xaa\x17\x88\xd7\xab\xcb[\xc1!-\x22\x10\
-2\x06\xd2m\xd6l\xd7\xc9\xc0\xa8\xa4\xd8\xe2\xc0\x97u\
-y\xd6b\x8ew\xc6\xb6\x0bi`-\x85\xb8\x0b\x8ck\
-\x8d\x22\x19\x8d\xf3\xe3\xd5\xbf\x1c|\xbc\xba:98\xfb\
-_\xa7\x1f\xd7\xad\xe9\x83o5\xfbtuX\xab<8\
-\xfdt\xf0\xe5\xaa#\xe7\xe8/\xf5R\xf5\xe0\xfa\xf6\xaa\
-[\xdd\xcc\x0b\xbd\xeai\xed5\x88d\xd9`f\xdd\xa4\
-\xaf\xf4\x1aW\xd49\xafq\x9d\xebHLZ\xc9j'\
-^\xe3\x8a\xf9\xb82\xc98Z\xe9\x8c\xb2]\x8e,\xaf\
-\x9fY\x8e\xdcg\x9a]\x8e\x0f\xe9\x98w3\xb2(g\
-\xb2\x98e\xac\xde\xda\x16\xca\xc0\xe6\xd5\xb9\x07\xce\xf4\xff\
-!\x1fXN\xa8{\xc6@\xee\x07\x1a\xbd\xd0@37\
-\xb6\xe4||\xa0\xd1\xd7\x0e\xb4\xcf\xf4\xfd\xab\x10\x08e\
-\x97l\x81\xa6\xa2d \xe2\xa6-\x0e\x7f\xe6Z6\xa1\
-H\x11)\xadlE\xc9!\x0c\xc3\x1a\xfa\xd09M\xa5\
-u\xce8Y\xf1\xe6\xfd\xe5\xea\xb8\xdew<H\xa1\xad\
-\xdc\xbb\x1b\xf0og'\xd7u\x9a\xe4\xe3\xd5\xea\xf2\xdf\
-\x87\xa9\x86\xff}\xf6\xb7\xab\xcdk\xec:\x8ds\xf4o\
-\xab\xeb\xf7\xe7Um\xadt\xe0\xb4\xf20o\xb9BX\
-o\xb5\x02\x87e\xee\xd0j\xde\xce\xeab\xdf\xcaj\x8a\
-\x02\x14\xcc\xda[\xce\x02a\xe9\xbd\xe5\x14\x02%1\xa8\
-\xb3\xdc\x0dT\x93\x88\x1f\xb7\xdcwny_\xea\xaf\xf5\
-\x1e\xf8j\x98m\xa8\xf7\x5c\xc3\xd7\xd3:\x91\xf8\x87\x12\
-\x0b|\xbd\x15\x0d\xc5A=\xd5;\x1a\x5c\x80$\x8d\xac\
-\xa3\xc1\x18\x98R={\x1a\x1c\x98U-\x1e\xa1\x81\x8b\
-\xc9\xae\xdc~\x9e\x86:\xefry\xf2\xf9\x0f\x04\xc8^\
-\x1c}\x81\xf5O;Z\x8a\x03\xa3F\x94\xc5\x92 \xc5\
-<\xcc\xb7\x22+c\xcdU\x1f#\x96\x08\xe2\xa4\xc9\xe6\
-\xbd\xd7\x90CPj\xf4\xe3\x05\x1d\x94\xc3\xfcq\xba\xfc\
-\xff\x03\xba4\xa0xjp?\xc4|\xed[\xd1\x91\xa5\
-\x05\x98\xfa\xb2\x15M\x1b\xb9\xb2\xf28Ye;\xb2\x90\
-\xbf\x09Y\x86\xf5#\x03Y^DYh\x83\xac\xa1\xc2\
-\x83\xd3\xfbd\x0dSC\xb4a\xfa0\x19\x14\xcd\x03\xea\
-\xd4\x8d\xb5\xa3\xe3\xa1p&dRHC\xab\x081\x81\
-*\x93tl\xf5*\xb9\xf8V#\xd1\xebggl-\
-\x1f\xd0\x85n\xee\x0bF\x07\x09\xa7\xa8d1\xa8{\xf1\
-\xdc\x8a\xac%9\xb8\xa7fv\x9c\xa5C\x0ezl\x93\
-:\xc7F\xd2\xb4\xe8q'\xfa(w\xb9\x95\xa7\xa9\x96\
-\xddq\x87\xc0\x96\xeeXIB0&\xd6\xd0\xe1kr\
-\xa8\xa8.\x10\x94\xd0\x91hA\x82\xc0R\xd4\x16\x86\x80\
-fVl\xcb\x1c\xa0`\x0f\xd2`AO\xe9\x03\x1a*\
-\xb0u\x03\xd4\x80\x065\xc9\x8f\x0e\xd0\xa0\xad\x5cNQ\
-w\xe8r\xa3\xab!\xa4\x13\xaa\xcb\x82\x91!\x86A\xa9\
-\xe2\x94\x1e\xb3\xcc\x8c\xc1:\xfa\x90\xbed\xf1\x9e(\xd4\
-V\x80Z\x81\xf9\x0c\x8d\x8be:\xb0p\x8a\xbe\xde\xce\
-\xecG8\x16\xdc\xd25\x91k_\xcc\x5c\x80\xcf\x8d\xc0\
-:\xa8\xc4@\x89\xb3\x94n\x10\x85CA\xf3\x22\xfd\x88\
-+@2f\x90n\xb0\xba\xbe\xea\x864\xe3v\xc4-\
-\x89\x0b\x0cZ\xea(`\xb04.\xa2\xab\xa5?\x85\xc4\
-\xde>\xc1\xed2\x09\x97\x82_A\xe2\xe1\xe9\xc9\xc5\xff\
-9\xb8~\xbf\xa9\xf8\x16\x13\xb46\xa0n\xc1\xc9v\xb7\
-\xfb\xa9\x8bVW\xbb\xbf\xbb\xbb\x8f\xfb\xe3q])z\
-S\xd7\x90\xfe\xf0\xfb\x87\xd6\xbd\x1e\xcf.[\xe1\xab\xeb\
-\xcb\xf3\xbf\xaf\xde\x9c\xd5\xf5\xe8\x9b\xef\xeb\x05\x9e7\x08\
-$\xa1\xa5~n\xf1\x81\x83j\xe8\x9b\xcb\xf3\x8fgG\
-\x9b\xe0\x7f\x9e\x9f\x9c\xf5h]\xb4Z]\x9e\x9e\xd4\x7f\
-\xde\xe8-vtP\x97\x86./\x0f\xbet\xca\x06t\
-\xbc\xdd\xac%\x81\xec\x06\x9e\xbc+\xad\xac\xfd\xdb\xde\x92\
-\x98\x80\x13\xcb\x82\x0b\x98\xa1+\xef\xfdy@\x19\xcc\xcd\
-y\xc1\x09\xecVx\xc0\x14\x5c\xdc\xa2\xc3\x0c\x0a\x13o\
-\x8a\xffPa\xbd\xf5(c\xf0t.k8\x18\xa8\xb0\
-\xddW\x16\x02\x1a!\xb4Yq\x18\x98&{\x879\xa4\
-p\xc9{\xcaR\xc0\xd0e!\x0e\xccR|]i*\
-D!\xe4\x85\x04\x18\xa6\xa7t`\x01\x8b\xe2\x5c6\xe4\
-\x15!]\xc5\xc6J\x1dA\x02\xdd\x16\xae\x9d\x92\x0c \
-1\xb7^G&(\xa3\x04m\x82\x05A\x0b\x09\xc5\x86\
-x!\x88p\x94\x1c*m\x06\x95*\xafE,\x87j\
-\x9b\xed\xa5@\x88bnp\xd4\xb0Fg\x13\xef\xc9\x0f\
-\x03!\x09\x1c\xe0\xd6U\x9d\xb2\xd6\xab\xad\xe2\xd6\xfb\x0d\
-k~\xd2\xeb\xa2*\x8da\xd9\x0c\x1b+%\x01aN\
-o\x1cl\x82\x8d\xadVA#v\xa8V\x02B\x85\xa5\
-\xb2\xdf\xa9i}\xd4ii\xbd\xd9\xc0\xd6\xef\x9b\xf2\xcd\
-G~\x98\xf4\xfd\x7f\xdc\x9b\x09\xb9X\xc7\x94\xd8\x98\xff\
-\xb8\x8d*\xbf\xe4\x90\xceL\xa0\xa2\xf6\x12!]\xbey\
-H\xd7\xf2\x8c\x90\xdew\xe4\xc3\x00\xc8$\xe0\x96\xd6\xc7\
-$&\x85\xa2\xc2\x9b\x01\x90)\x00I):,\x81K\
-\xe6\xbd\x00\xc8z\xc3\x7f\x1f\x00\xd9\x15,\x90\xca=e\
-n\x90\xa6\x856+\xf6\x80\xc2\x96\xdea\x05\x98\xd0\xf2\
-\x9e\xb2\xa8\xe2)\xa5\x0f\x80\x1c\x01\xe4\xe9\x9b\x01\xb0\x81\
-m\xc84\xf9.\x00\xb21\x84&\xaf\x03`+\xd4\xc6\
-i\xa7\xa3\x0d\xe9\x06\xb6\xc1\xdf\xc4\xbb\x00\xd8\x0c\xeab\
-R\xb3\xbd\xc5\x9f\xc6Q\xc3\x1a\x9dM\xbc#\xbf\x0b\x80\
-\xad\xab:e\xadW[\xc5\xad\xf7\x1b\xd6\xfc\xa4\xd7\x85\
-\x0e%\x8d\xfa\x00Xa\x83@\xd4.\x006\xb0\xb1\xd5\
-*\xe8\x02 \x0b\x021\xe6\x10\x00;5\xad\x8f:-\
-\xad7\x1b\xd8\xfa\xbd\xc9w\x01\xb0\xd9\xd4\x05\xc0\xa7]\
-\x0a\xc9\x7f\xbbK\xa1\x9f\x0e\xe9}({\xb1\xbb\x8f]\
-\xdd\x18M\xdf\xbfp\xfc\xfa\xee_\x0a\x01R!\xe4]\
-$:\xca]'\xba_>\x81\x99\xbb$\xd0\x7f\x1d\x04\
-\xb6\xcb\xad\x1d\x13\x88\xe5\xd7\xe7\x81EwI`\xfc\x0a\
-=\xd0vI mK\xe0oIdr\x82\xbb\xec4\
-\x89\xfc*o9\xb9\x14\xde\x96\xc4\xdf\xa6b\x7f\x92\xc4\
-|yO\xdc\xe1z\xfbR\x11\xc24Y\xa6\x99x\xf9\
-\x9e\x9a&Q\xbf\xa5'\xaa\x80\x86\x86sg\x1f\xa1\x01\
-\x87*w\xf6\xb9C&%Zg^\x12\x08[\x84u\
-V\xba\xce<\xee1\xbf\x1c\x84\x10\xc4\xa29,\x9c\x11\
-;Z\xd2\x02\x81D-X\xeb\xb7pT\xa7X\x04\xa8\
-\x9b1\xda\x82\x11(\x94d\x17aU\xcao\xfd\xf0u\
-\xfd\xb0$D0Q\xcd]v\x84\x10\xe5\xb7\x9e\x0d$\
-\xd2\x9d,\xf0\xf4s\x19\xbdM\xdb\xcfe\x90\x83\x16C\
-\xc4\xd4_\xd6\xba\x8e\x17\xc0\x22a\x0b6p)\xb8\x9e\
-i\x0c\x02\x96\xd4RF\xb8`\xc9\xac\xa0\x00G:/\
-\xd8\xc1\xc2M\xacb\x0a\x91\xc4U<\x810\xa2\x8c\xe2\
-\x85 \xd0\x8a\xe4B\x0dPX\xc3\x1aX\x16\xc1\x10j\
-\x8eeC>\x0bx \x17\x1f\xe4- \xcd-xA\
-\xe8`EK-*\x08\xa4\xa2R\xee\xc0\xda&\x12`\
-\xca\xe8\xe5e\xad\xe8NO\xde |\xd7\x1co\x92}\
-\xcb\xc9A\xd5\xc9u\xc1\x0a\x99\x051\x86\xe9/ps\
-&\x1b\xc0B\xe4\x9c\x15T\xb8\x95\xbe\xa3\x8ds$3\
-m!\x04\xe2\xae\xe6#H\xc8J\xba\x905o\x18w\
-\xd2R \x8a\xf1\x8dn\x05v\x22\xd1\x85!(\x16r\
-k -<*\x88\xe4Mw$ )\xea\xc8\x99\x18\
-h\xd6\xcfxo\xe9\x1c\x85\xabnc0\x22\x92[\x8c\
-*\xe6\x02\xc4\xf7\x84C $3\xca\x9d\x96h`\xde\
-\xb5'n\xa5\xfb\x86;\x82\x17\xb2B\x0b\xa9\xd2\xecQ\
-\xa8\xaa.P\x9c\x8a\xf1B\x04\xa2\x14\xc1A\x9a\x80s\
-\x94\xaf\x22\x81\xb7\xf2\x0c\x8ehC\xcc\x090%\x0e\xaf\
-\xa0\x81\x97B\x12\x83\x0b\x9a!\x9bNz\xeb?\xf6\xaa\
-\x17\xab\x8e\xadb\x07\xb1\xdb\xae\xd4\x046M\x8e\x0a\x8f\
-\xad\x22\xa9\xad\x220\xa3\xc8\x0a\x16H&u[\x83C\
-+\x8b\x91\x8dS\xe5k\xc4\xed\x16\xf9\xf3\x1a\x91\xe4j\
-\x8e'\xb8\xb9\x10U\x10\x81(4i\x11\x04\x94\x14\xaa\
-Uo\xdc\xb8t0\x98\xder\xa4\x06\xaa\x86\xbc\x08\x81\
-\x82\x99\x92\x15c0\xd3\x92w\xe0 \x8dk\xb7\xec\xa5\
-% \x93\x8d\xe2N\x11W\xd0A}P\xbf\xd9$\xf1\
-\xae\xe5?\xdc \x22\xcd\x96Q0\xd4R\x067-\xac\
-\xca1\xaa\xe0d\xa1\x81\x98\x12\x96j\x15K\x88\x9b1\
-\xb2i\x0a\x02\x99Q\xe1\xa1\xbb\x884nl\xc1\x92\x88\
->v\x02+\x1aMt\xcb\xe4\xb2\x19\x91O\xcc\xb1\xfe\
-*\x92m\x09p\xf7\xa4\x1d'[\xfe\xe6\xc9\x16sG\
-KoD\xf8 G\x91;0;f\x9f\xa4\xc8\x13$\
-0y3IQ (a\xb1\xcd,EAPH,\
-\xef\x05\xfbLHI\xf6\x96\xa66\xc1\x96\xa6Z\x05}\
-\x9e\x22S(\x99e3M\x11\x07pXx\x97\xa6\x08\
-A\x8c\xf0\x9e|\x11Pv)\xd1R\xd5-\xa8\x18-\
-[\xb5\x0a\xee[@\x02\x16\xa9e3]\x11%D\xa6\
-\xe9f\xba\x22f@\x0c\x91>c\x11\xdb@-Q\xcb\
-X7\xa0ht\x19\xabU\xd0'-\xaarE\xd4[\
-\xd2\xda\x04[\xd2j\x15\xf4\xa9\x87\x84\xc1\x99\x986\xf3\
-\x16i\x01WQ\xdfL\x5c\xe4\x08l\x0f+\x08\x84\x0c\
-\xe2\x96\xba\x1a\xd62W\x13\xbfo\x80\x05$K\xe1\x96\
-\xbc\xd6 \x16\xe5\xdcL^d\x09Jb\xd9g/\xb2\
-\x02!\x9c\xb1\x99\xbd\xc8\x19RH\xbde\xaf\xce\x8f\xfb\
-\xf4EJ\xeb\xa6\xf5\x19\x8c\xd4@2\xc863\x18i\
-\x82\xa7\x12\xb5\x0cv\x03\x0a\x8bti\xac\xc1}.\x1b\
-\xe1@\xeb\x12\x07i\x00k\xe9s\x19\xa9\xae\xfd\xbeO\
-G\xa4\xf5(Bl3\x9b\x91\x14\xf0\x0c\xa1\x96\xcd*\
-\x167n\xdb\xcb\x8b\x01\x92\xa6n\xa63\x12\x01+\x8a\
-\xd1\xb5J\xa4Y\xd0\x0ckp\x97\xd8F\x18\xbd\xd0f\
-b#QPR\xd7\x96\xd9\xd6-\xc8\x9b\xf1\xd45,\
-\x803\xacKm\x83a,(\xd2R[\xd7e]v\
-\xdb\xfe\xee\x81\xff\xfb\xdd=L\xa4\xe9\xdf\xee\x89\x9f>\
-i\x8e\xbbL\xd3s?\x0d\xe3\xa4\xd9jf~;6\
-\xfd\xab/Ny\xe4\x97c\xc2\x19\x9c\x91\xad\xc8\x8c\x11\
-\xf3\xbf\x1dk\xab\xe1L\x80B\xdc\xffZF\x08$\xdc\
-#\xfb_\xd6 \xb8k\x1aw\xab\xe3\x85!+(\xba\
-\xe5\xb3\xc3\xc0\x22\xcc\x5c\x16\x04\x85\x0c\x8b\xd2\x0e\x1e!\
-f\xb6\xed\x1e\xd3V\xdf\xc6\x11fYS\x07\xe6L+\
-\x1dmV*j\x89\xd1\xd1\x16\x90%\x84):\xdaZ\
-\xd9mis\x16\xaf\xb4\xed\x84.,\xdf\x94.\xa2\x00\
-a\xf1\xdc\x82.F\xe0\x94\x0c\x9a\xa6\xeb\xd9\xc6\xbb[\
-le\xbc\x13>\xcf\xf8\xf9\x07Y\x08\xdc\xc8\x89K\xed\
-\xd3_.]\xb63\xba\xe6c\xac\xab\xe5\x8b\xc4XW\
-\xc7Gb,\xa7\xaaR\xc63bl\x9f\x9b\xb6\xf9\x1d\
-V\x14#\xa4\xf5\xaf=\xda\xd1\xb2\x80\x858\xb9\xd7\xaf\
-\x02E\xc2X^\xcf\xa4\xeam\xbb\xb9]T0\x98\x15\
-M\xef/*(\x81\xd4$\xfb\x9fl1\xa0b\x98\xb4\
-\xcb\x87\xc9\xb2\x87\x13e\xa7\xf2vq\xdbj\xb1\xbb\xb8\
-\xca3\x86`S?Q\xed\xcc/\xd1\x8b\xabM\xfd\x8a\
-}n+\x8e\x89\xfdc\xfeX[8\xaf-&\xb4\xd1\
-\xe3\xda\x9c\xa7\xb4\xedj/\x02\xb6\xc89\x96\xd8\x12\xbf\
-\x9e\xa5\x88\xa7\xb1\xc4\x96\xfc\xf5,\x1d\xd2K\xb2\xe4\xaa\
->\xbf\xab\x85\xe6\x13|i\xfc|=K\xae\x863,\
-m\xa9\x0dw\xc1\xd2\xf6\xc9a\x96F'~\x0a\x8do\
-\x8f\x13\x9f@\xa3\x93\xce\xd08\xabm\xf74\x0a\xcd\xb3\
-$\xf2\x84!\x89\x12\xf8$\x96\xc4\xbe\x9e\xa5\xb7\xc7\xb6\
-\xc2\x17di>\xbc\xfb\x13\xc3\xbb\x9b\xdbSX\xd2x\
-\x8a/\x1dUoz)\x96\xd8\x1c{\x96f\x1ac\xe5\
-\xa1\x83\xccP\xd8\x02\xb7s\xc7\xd2\x9c\xb6<B\xdcJ\
-\x1bMk\xd3\xdd\xf9R\xe8\xbc/\x85\x7f\xbd/\xbd}\
-\xe2\xa5\x82{\xe4S|\x89\xea\xe7\xa5|IXb~\
-C0)O\x19q\xab\xb7\xf9\xf6\xebY\x12V\xfa\xa5\
-%A.\x05\xe7X\xe2R\x9e\x90\xe3\x0e\xc7\xcf\xd7\xb3\
-\xc4\xa5<%\xc7\xd1\xf0\xe7\xa5.\xa8\x04\x99f}\x09\
-\xf9\x099\x0eq\x9b\x11\xf7\xd5U \x90\xb9\xb8\xb8N\
-\x86C\xb0W\x93\x06\x94-\x9c\x18\x85&\xabtfW\
-\xaa<=\xa1\xb1\x9e\xc1\xc1!\xdb\x0c\x22\xe4\x99\xe4\xbe\
-\xbdZ\xf1\xf1O\xcc\xf9\xc9\xf4n\xa7\xd3\xfb\x84\xb2\xa9\
-<o\xdf\xd1\xf9\xfdL\xe7\xf7E\x9d\xdf]u~\x9f\
-\xd6\x99{\xd8\xb9\xed\xc6\xe6'\xf1\x1e\x89J\x1e\xb4\xfd\
-\xec\xc1\xf4\x04S\xdbNH\x08\x828\xd4\xe7f\xae*\
-Z\x12\xc8\x83\xc2\xb6\xda\xb3\x86\x5c\xcdB\xee\xf6\xac)\
-N\xc3\xba\x829\x14B\xe3\xfa\x95 \xc3J`y\xfd\
-\xb3\xd2\x99\xb1\xcb\xcd\xb0R@\x89\xcb\x02\xc1\x15\xd3l\
-~\x1e\xa8\xf5\x11\x13`\xd1R\xb4\xd1\xbeF\x09\xa9\xa2\
-]\x17\x91\x01e!\x91\xae\x8b8\x001\xd2t\xe2\xc9\
-\xcd\xdd1Z?\x8f=\x81\xea\x05w\xb9#\x8d\x9b\x87\
-\x88\xdd8\x12\xb3rY?'\xe0.Y\x16KQ\xa0\
-\xc4(?\xc5\xf4\xc5\xc1Q7\xe1\xa5\x0c\x81(\xc6\xfd\
-\xe4\x18\x0aXb\xa3\xf3x\xb2\xe8qWtbv\xee\
-e]\x19\xf5QW.\xfe\x84\xc8 \x05B\xa9\xdc\xff\
-M%\x09\x98\xa6\x94V\x96'\xcbVtiPX\x8c\
-3\xb6}\x80\xddA\x17\x0cd\xab%\xbf\xe8\xe0\x17.\
-\xf6\x18c\x81\xf2\x04\xc6\x96\x8eP\xd4\xd8\xa8\xa7\x0c\x0d\
-R\xd0\xfa\x81\xba\xb4\x02J\xc6j\x1dgj\xe0B\x8c\
-\xf1s\xc6\xbe@\xdb\xce\xfcg\xacy}\xa6\xd9u\xb6\
-\xf9\xdc\xd3\xd6\xef~^\xba\x9e\x9f*\xe6WV\x1bm\
-D\x06\x0fWu\x83\x00S\x0b\xe6\xcc\x0ap\xb7X\xfc\
-\xb3\xb2Vv\xcb\x9a\x12\x17\x14\x1eR,\x151\xcd\x17\
-\xcb\xb1\x02\xc5\x09\xb5\xa74\x81\xc5\x8a\xfe\xbc\x03\x97\xe8\
-7Nw\xce\xa9\xfc\x828\xb5\x02H\xee%\xeeo\x11\
-\xec\xa8(\xd4q\xea\x02jj\xd8ge\x22\x10+\xa4\
-\x13\x83\x7f\xdb\x15\xcf\xfb\xfb\xda-3\xbb]\xed\xb6\xa2\
-k\x07W6*\xac3[\x01\xb6=\x03g6\x17l\
-\x9b\x10VZ\x9e\xb6\x10<\xb9K\xe2\xd4&\x89K2\
-\xb0~\x93\xc4\x1d\x92&\xaa\xe5\x91\xebp\x15\xa6\x99m\
-'\xfb=*\xfb\x8d,g6\xbb<\xecDg\x5cl\
-\xda\xdf\xb7\x1bG\x5c\x09\xdd%i\xec\xf8\xa8\xa7Q\xce\
-l9\xddmO=\xb3\x81w\xb7\xd9\xf7\x9c\xc3\xcd\x8f\
-\xc3\x92H\x8a\xe5f\x1c\x22h\xc1\xa0]\x913\x7fg\
-\xa7B\xdayT1\x084B\xea<\x8a\x12A\x84T\
-\x7fbS\xd9\xc3I\xc9\xc3N\xf29\x8f\xe90\xee\xd8\
-c\x90\x1f\xf7\x18\xbc\xbf\x8f\xb0\x07%\xf5y/\x13B\
-D\xcb\x83\xed\x89M9{\x87I\x07\xd3\xa0|\x1e\x09\
-\x04\xc9\xee\x14\x0b\x01\xd1t\xe1\xfc\x96\xa3\x08\xa3\xe3\xc4\
-\x09(\x1d\xdd{N\x18\xd8\x8a\x92}+R\x96\x05\xa1\
-X1[,c\xf8&\x5c\xe4\x9b\xb2\xa2\xbd\xa7\x04\x90\
-b\x14\xe9X\x19\x93\x13\x86\xddc\xc5\x14\xd2\xcd\xa2c\
-\x85%\xd7\x06=\x8b\x96\x12\xbb\x1b0\xf37\xdd\x22\xec\
-3{\xdbw\xfb\xe0\xcf\xec\x99\xdf\xed\xaf\xff\xcc<\xf4\
-\xf2\x96\xf3S\x93K\xff\x9e\x84\xfe}\x0a\xf3O\xe9\xb1\
-\xb3>\xe5!<v\xf6\xf9Wd\xec\xfaA\xe7\xe9\xc9\
--\x9azn\xa7_hy\xd6kV\xda*\x9b\x8fa\
-fN\x19\xd8\xf3^\xb4\xd2\xd41\xce\xab\xa3g\xbcf\
-\xa5W\xc6;[\x1fu\xc2\xe7uI{;\xd0|\x97\
-\xf0s9jo\x07\x9aW\xa6O}\x1b\x0d;\xfa\xfc\
-k\xa2\xfa\xd7J\xcd\xbf\x86\xaa\x7fm\xd5\xd3\x062\xe6\
-v/\x95z\xf9\x81\x8c\xcf\xf3\x9a\xf6&\xb2\xf9\x8e\xc4\
-gy\xcd\xfc\x9b\xc8ze\xba\xb3\x91eE\x9f\xc9\xd1\
-q\xfdl\xc5\x91\x15\x7f\x02G\xf3\xcapZY\xee\x8e\
-\xa3\xccgr\xe4\xb2*[r\x84\xdf\x92#\xde!G\
-\xfc\xdc\x08=~\xb6\xe1(\xf5\x99\x1c5e\xf3\x1c\xa5\
-\xef\xf0\xb9\x04\xcd\xdf\x9eJx\xe6\xbd\x0d{\xd8N_\
-x#\xc2\xac\xe3\xb4G;Z\x122\xa0E\xf1\xc52\
-\x14L\xc2\xc5^O\xdd\x10\xcd\xdd<\xf57Z\xd37\
-e?/\x9b\xf9\xe2l\x92\x80X\xbaK\xc5\xb4\x04\x15\
-\xa3\xd7\x93\xb7\xdc3w\xe7\xdd\x9d\xfc\xf4]\xff\xcbR\
-\x89\xfc(\x95I/O%\x81fQ\x1d\x5c\x14\x0a\x17\
-\x13\x7f\x06\x97\xfdLQ?\xa9\xf4\xf3>\xd8\x91/8\
-\xc6Q\x10\x91\x17\xcbR\x00\xb9Hz\xe5\x92\xc1]\x0b\
-\xf9\xeb\xe9Y\xc2\x86\xce\xcfEN\xcf[\xf63\x94?\
-\xeb\x88\xcf\x9d\xae\x92\x92A)\xe18\xbe\xbdI\xa5\xa0\
-\x95\xb9\xd5\xa7\x17zA\xe5\x8b9\xec\xfc\x0a\x08{\xe1\
--I\xdd\xe5\xa2\x0f\x0b\x98R\xaa/\xb4\x80\x93\x9b4\
-\x07\xde\xf6\x8db\xdb\xbfC\xac_\xb5\xf9y\x1f?z\
-rx\x98_y,\x0e\x88,\xc5o\x9e\x1bd\xb5\xa8\
-\xac\xee\xf8\xcdb?\xe7\xb3H^b\xf7o\xe5|\xa9\
-\xb7\x90\xaey\xfan\xffhu|5~\x1b\xb76j\
-\xfb\x17\xa5\x01\x93\x8b\x8d\xb91\xd8%\xa3\xeeaB\x01\
-\xa6\xc5T\x17\x8e\x10\x98\xc1\xc3\xbb\x1a\xc8\xc1\xdc\x19+\
-J\xa0$\xa5\xc8^\x8b_\xce\xa0\x96%c\x13\x93*\
-\x81Ei\x90n\xa8\x82;g\xb1\xcd\x1a\x0d\x02#\xb3\
-l\xea\xf6A\x0b\xd9\xd0\xa2\xac\xd2(9\xb6\xd3@\xd2\
-\xc7\x16\x15\x04T/1\xa0\x09H\xee\xbaWn\xf5\x8c\
-\x98d\x11\xef0^7\xa9\xd6\xb9\x81\xda\x0d\xf8\xe7\xae\
-(\xb8\x97D\xdd\xcb\x84\x12\x81\xa9\x8b\x02\x88\xe1\xea9\
-I\x5c\xddc\xa5\xdb0\xaa\xa2\xa5B\x93[\xae<\x1c\
-\x93\x0f\xb6\x5c\x19\x0f/?\x9e\xae\xde\xac~\x5c\x9d\x9d\
-\x1f\x1dmn\xc2R{\xf6\xb7\xfe\xfc\xe6\xfd\xa9\xd4\xf7\
-g{\x0e\x9fM=\xc9u\xe2\xfd\x22-\xc9\xed\xa6\x8b\
-\x13\xf4\xc6\x22\x04g\xd1\xb1;2@\x19\x8d\xd6hf\
-0\xed\xa5\x83\xa4\xc4\xdavDd\x8ej\xe7\x9d4\xdd\
-v\xe6\x0f\x83t\x06\x8fh\x01J\xabhO\xa8\x03r\
-\xf1B\x934S\xcf3\x83+[\x96\xbd\xc2\x80\x96\x9e\
-c\x9b\x14\xc3\x91&[\xff\xc3\x14:\xc5\xbel;\x9a\
-\xb2|\x1d\xd5\x7f\x5cO\x91\xae+[\x7f\x17\xc9x\xfd\
-\x13]\x10\x0c6r\xbav\xdb P\xe6B<`\xc4\
-\x11\xb9\x17\x08\x92\x8e\xa5\x0c\x90J\xe1\xf4=/\x83\x14\
-WscL\x8d\x03\xd7\xce6\x98\x8f\x03\xc3\xea\x19w\
-G\xb5\xda\xe1_\x01Lr\xad\x15:\xa0\x13F\x19\x18\
-Ju\xf7\xbe\x15?t\x87w\xe4]O\x5c\x1f\xa5\x90\
-+\xf1\x98\xb9\x97\xe3V]\xea.c\xcf%\x88\x1a\x96\
-\xd7\x0f\xa9\xb7\x9fr\xfc@%*\x19\x1b\x8e\xffp5\
-\xedE{#\x1d\xc2\x8c}\xed\x90\xa4\xe8^\xe9`\x02\
-&w\xb4!\xba\xb9`\xa6\x0cQ\xab@\x94\xd4\xac\xa8\
-\x00j\x96\x12{\x8c\x80l\x9a9D2.\x1c\xca\x83\
-4\x11E\xf8\x10\xc9$\x0a\x0a\xad\xa3\x16y\xfa\xa0\x89\
-\x10\x84s\x0c1Y\x80\x9d\x8a\x0d\xa8\x80\xa6\xa1\xed\x15\
-\x011c]cn\xa2\xd4\xb0\x0d\xe9\x1f6\xd1\x00O\
-\xe3\x18\x87SC\x152\xa4\x0c\xb1\x918s@\x04\xcc\
-]\xb8LY>5lbb\xd8LF\xa8\xdcM\x12\
-\xe2H0C\xd5\x05\x13\xa8\xebh'\x93\x02\xa1i,\
-B \xd1\x8b\x95j'\x13CP\xf1\x8a\x1a(\xb9!\
-\x8dXQ\xb2E8$'I\x8c\xc2\x88\x82\xeb\xed\xf5\
-\x9c\xd0i\xa82bA\x5c\x00#\xdd\x87\xca\x92*9\
-\x0c\xee\x98\xf5\xc0\xc6\x834\xca2\x1e\xb5\xa2?\x8c\xc7\
-,P\xb8\xb0p\x15\x1d\x8f\x11BRl(M\x90\x1a\
-$\xc3\x10eSN\x994j\x02l#o\xe6V\x1a\
-!\x93\xd0=\xeb\x18,\x09Z\xca0-!\xe0\xc8\xae\
-\xa6\x13Cp\xe2Zbs\x87\xb4\xe9HX\xe2\xf5\xbd\
-\xfd\xda\x00#\x02K\xbc\xe8\x9b\xab\x9a\x07M\x0dfz\
-d0\x17\x88\x10\xa7\xd1\xf1\x1d\xc5(\x87!\x96\x90\xca\
-\x98k\x94KJ\x8e9\x8b)m\xc4\xb2 \x9b\x8f\x03\
-\xc2os\x93\x96,l\xb7\xa1\x80\x10c\x0c\x05\xaa\x12\
-|\x1b\x0a83\xc7P\xe0\xacY\xd6\xa1 #u\x1d\
-\x0a\x8ac\xacC\x81a\x8c\x91 -\xd7\x1d\xcf`\xa6\
-D9^\xd5`a\x8aZ\xa58\xa4\x92\x86,\xbc@\
-h\x18\xe6\x9e1\x84\x8f\xf7FA\xe0L\xe1\xebL\xe0\
-\x5c\x8a6\xacJG@\x88\x16\xcd\x0d4\x0d<]q\
-,IQ\x10\xcbFl\x08\x04Qv\x92.\x8e\xa8\x00\
-\x16w\x93\x07\xd1%D\xd3\xfa\xe8b\x10\x8a\xee\xb1W\
-\x08\x92\xb9\xc4H\xa7\xa99O\xf5\xc5\xc3\xf0\xa2\x8c[\
-gezl[\xc1m\x1c\xc2\x82L\xca}\x87\xb0\x12\
-iv\xcf!,9\xf2\x9eC\xb8\x17\xf5\x07\x0eA,\
-c\x1cg\x04\xc1\x22\xa5,\x9c\xc1H\x07\x00\xd3\xad\xd0\
-\xe0!\xa2\x12\x98c!2\xc7\x8a)\x10z(\xafE\
-U\xdc\xc8\x87\x92\xae\xea6J\x07*\x8a\x0c\x18){\
-\xe1M\xc5\x0c.\x16T\x9b\xb3\xd9H\x07-\xc8>\x9a\
-\xd8\xcc1\xc8$oF\x0f\x883Qd\xa3g\xc0\xac\
-h:U\xd9\xd6\x99\x03*^\x9c7;\xdd!\x84\x91\
-6\xa1\x04wM.\x0f|F\xc9\xd0\x1f\xf8\x0c\xa6\xe7\
-}\x9f!q\xa5\xa9\xfez\xe04\x82\xea\xdb:M\xe4\
-\x13\x9c\xa6\x10H\xb0\xd9\xdas\xc5\xb4\xf8\x9a\x95\x12%\
-\xd6\x8c\x92\x07\xa5\xef\x15\x06\x11*4bE4T6\
-1\x87\x0cE\x1a\xa2HC\x95\x81KP\xf2v\x03\xac\
-0\xa9\x8dd\x93\xa8\xae]6\x0aI\xe1\xc9v\xfe0\
-\x85\x8e{\xb12C\x86\x14\x1c/J\xb2\x84\xd9\xe8\xcc\
-\x02\x16\xa1J}(\x0aH\xd7(](\x12\x88\x94H\
-\xdb\x080\x81`\xe9B\xde\x87\xa2\x04CB\xe2\x0d4\
-\x1d0L}\x1d\x8a\x0a\xabQ\x1f\x8a\x14\xdd\xa2\xa3\xc4\
-\x0b(\x19\xf3\xd0\xa04\x90 \xb6\xb1\xa8\xb0\x15.C\
-\xc4\xc3\x08\xcc\x1c\xb0d\xe6b{\x9e`R<\xa8a\
-U\xda\x18\xd8\xccs\x13\x15\x87\xa4`-\x83\x1eT\xcd\
-\xe0i\x8a\xa6\xd0\x09\x9f4\xdd\xda'm\xd6'\xbf\xdb\
-\xbf\xfa\xf1\xdd\x9f~\xf7_\xea_?\x7f\x00\x9a\x00\x00\
-\
-\x00\x00\x15,\
-\x1f\
-\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xed=ko\xe3F\x92\
-\xdf\xe7W\xf0\x9c/1N\xa4\xfa\xfd\xf0xf\x81\xdd\
-A\x82\x00\x17\x1c\xb0\x9b`\xf7[@K\x94\xad\x8b,\
-\x1a\x92<\x96\xe7\xd7_U\xf3\xd5$[\x14\xe5\x91'\
-A`;\x89\xa9\xea\xeaWu\xbdY\xad\x5c\xffm\x7f\
-\xbf\x8a>g\x9b\xed2_\x7f\xb8\xa0\x09\xb9\x88\xb2\xf5\
-,\x9f/\xd7\xb7\x1f.~\xfd\xe5\x87\xd8\x5cD\xdb]\
-\xba\x9e\xa7\xab|\x9d}\xb8X\xe7\x17\x7f\xfb\xf8\xee\xfa\
-\xbf\xe28\xfa\xc7&Kw\xd9<zZ\xee\xee\xa2\x9f\
-\xd6\xbfog\xe9C\x16}\x7f\xb7\xdb=\x5cM\xa7O\
-OO\xc9\xb2\x04&\xf9\xe6vz\x19\xc5\xf1\xc7w\xef\
-\xae\xb7\x9fo\xdfEQ\x04\xf3\xae\xb7W\xf3\xd9\x87\x8b\
-\xb2\xc3\xc3\xe3f\xe5\x10\xe7\xb3i\xb6\xca\xee\xb3\xf5n\
-;\xa5\x09\x9d^4\xe8\xb3\x06}\x86\xb3/?g\xb3\
-\xfc\xfe>_o]\xcf\xf5\xf6;\x0fy3_\xd4\xd8\
-\xb8\x9a'\xee\x90\xa8\xb5vJ\xd8\x94\xb1\x180\xe2\xed\
-\xf3z\x97\xee\xe3vWXc\xa8+#\x84L\xa1\xad\
-\xc1\x1c\x87u\xb5_\x01)\x0e.\xc6\xb5\xfa\xb3\x03\xf9\
-\x1f\xe0\xdf\xbaC\x05H\xb6\xf9\xe3f\x96-\xa0g\x96\
-\xac\xb3\xdd\xf4\xd3/\x9f\xea\xc6\x98$\xf3\xdd\xdc\x1b\xa6\
-\xa2~k\xde\xd6\x91\xac\xd3\xfbl\xfb\x90\xce\xb2\xed\xb4\
-\x82\xbb\xfeO\xcb\xf9\xee\x0e\xb8\x81\x19\xf7\xf1.[\xde\
-\xde\xed\x9a\xcf\xcb\xf9\x87\x0b\xd8\x1f\x17\xa4\xf8\x5c\xad\xe0\
-\xaa\xe6#\x92pV\xa0\x96\xc3\xfaM\xc2$4\xdaX\
-\xad\x88Ci1_k\xb8y>\xc3\x15~\xb8xH\
-o\xb3\xf8K\x9e\xdf'0\xed\x97\xf6\xc0\xf9\xe3\xee\xe1\
-q\xf7[\xb6\xdfe\xebb\x1c\xd8\x99\xb7M\xd7\xec\xfa\
-%\xad=\xd6\x03d\xfb\x87|\xb3\x8b\x17\xcbUV\xcc\
-6\xbd\xcb\xef\xb3\xe9\xc3r\x0d\xfb\xde\xe4\xf00\xdbN\
-\xf3\xfd\xf3m\xb6\x8e\x973`\xb5)\xf4[\xa57\xab\
-l\x9a\xcevK\x07\xb8OW\xab\xa90{a\xa6\xdb\
-u\xfa\x10\xc3\x80y\xf2\xb0\xbe\x0d\xce\xb4\x9f?\xc0\xd1\
-R.\x83\xad\xcfu\xebGh\xbe\x9eg\x8b-\xa2\x15\
-T\xc7O\x5cP\xe2\xda\xa0\x15\x18'K7?n\xd2\
-\xf9\x12\xc4\xa5\xc0\xf3\x86\x9c\xe5\xabU6\x83\x93KW\
-O\xe9\xf3\xf6\xa2F\x80\xa1\xda]\xb9\xa5\xaa\x1c\x14\x86\
-\xdd\xee\xf2\x87\x0a\x17\xcec\xf7\xbc\x02\xb2 0\x86\x11\
-\xf3\xcd\xd5w\xf4\x86I\xce\xdf;P\x0e\x0c\xb4\xdc=\
-_\xd1\xf7\x17M\x9f|\xb1\xd8f01\xf1`\x8em\
-\xa0\x07\xcc\x05Je\xfau\xb3\x91\xd0l48\x1b#\
-\xf5l\xd7\xd3\xf6\xb6\xbf\x8e\x8cNn\xaf\xee6\x19\xe8\
-\x99\xef\xfe\xf3\xf3\xff\xfc\xf4\xe97\xfb[\xac\x06\xc8\xcc\
-\x0c5\xa2n\xbf-\xa1\xbf\xae\x97;\xd0$\x8f\xdbl\
-\xf3/\x94\xc6\xff]\xff\xba\xcdzX\xbfl\xd2\xf5\x16\
-D\xff\xfe\xc3\xc5\x0e\x1fW\xa0|\xbfg6\xb1\x8a+\
-i'1\xb0L\xa2\x14\x93\x97\xcd\xfa(\x90DX\x90\
-E\xab\x1a\xd2<\x03\xd4\xc8\x84s!H\xb3\x96=\x03\
-\x5c)p\x04\xe3\xe12\x1f\xb7\xa6\xe2\x01z\xc1v\x03\
-T\x18\xb7K\x5c\xab\x15\x09\x17\xdc\x10\xdeZ+%\x0c\
-\xc0B\xb7\x96jT\x22\xb9\x94\xd6\xb6\x96\x0a\x03H$\
-\x869\xc4\xca!\xb6\x0c0\x9c\x9c\xe1\xef\x00{W\xcc\
-\xa5X,\x0f\xb3r\x85\xa5\x85f\xf1\x91)\xb3\xc5\x82\
-d\x8b1\x12\x95p\xca\xadPz\xdc\xc4$\xa6\xc3\x13\
-\xa7iz\x93\xdaQ\x13k\x06ZB){x\xe2\x90\
- \x86\xe8\x0bG'\xe9\x18\xfa\x0a\x8f\xbe\x7f\x06\xe1=\
-\x95\xad\x03\xc2{\x9f\xee6\xcb\xfd\xf74\xb1\xf8c\xe8\
-\x84\xc0\xaf*>Y\x09r\xccXB8cz\x12+\
-NA -\xb3\xdf@\xa6q\xa1\xe9\xeaU\xc8\xd8\x1e\
-\x1a\xc9h\xceFF\xa0\x95\xfb1\x8e\x8c\xe5'\x0aT\
-\x14\x0a\xf6\xcd)>R\x0d\xbb\xe5\xba!\xe2l\x8fD\
-D\x04\xe6i\x90\xd93\xba8\x04\x87\xa0\x0dt\x11\xc4\
-]\x04q7\x1f.\x90\xb0\xe0\xfb\x1cS\x95'\x91\xb5\
-=\x86\x16\x96\x0ds\xa9%_O\xde\x03&\xc6 \xe3\
-Q\xde\xe5G\x9dP\xaa\xba\xdc\xa8\x8d\xe6\xa6\xcb\x8d&\
-\xd1\xd2\x18\xde\xe2F\x0aS0nGX\x98\xd3\x1d\x1b\
-G\xad\xf1\xae\xc6\xc2\xfd\xbc\xd0\xb1\x81\xb9\xc4I\x8eM\
-h\xb6\xd1\x8e\x0d\xcc\xa6\x8e\xe9\xc6s\x08u\x87\x9e\x94\
-\x9aa\xe1\xf6\xb8s\x1c\xf7\xa14\x1a\x9d\xc8\x96 \x82\
-3c\xb4$\x9e6CA461\x82\x1a.[\x82\
-\x08\xeaPjmmK\x10)\xa0j\xc6H\x7f5}\
-%B@\xfbRI\xb8\x14\x13\x88\xa2('\xe0n\x10\
->)\x1fQ\xb7 \x82\x90\x0a\xb4\x09O,W\x94q\
->\xa1\x14,\x22\x01\xddz9\xc63\x0a\x90q<\xa3\
-\xcc\xf9b6\x8aQ\x82lI=\x0f\xf8\xb0\xafPE\
-w\x9d\x01\x13)A\x8b\x12O\x90\x83+\xbcI\x17r\
-\xd1q\x99H\xc2\x80\x8e \xee\xec\xfd\xa8\xf9Up~\
--\xa5b\xd4;\xc7\xe0\xfc\x86\xdf\xc8\xec\xa6;\xbf\xb0\
-\xe0MZ64\x7f\xd0=\xd1\x8b\x99\xea\x8e\xa5\x8d\x10\
-\x86i3Z>\xc1\x90\xff\x01\xf2\x09+\x1c\x90O\xcd\
-\xbc\x83tfP\x83\xee\x06\xcbF[\xd2'X\xa2\xa4\
-\x96\xac%|}\xd4E\x08\x15d\x8f\xb3DR\xa6U\
-?\xd4\x09\xf9A\x1a\xf8\x8b\x17\xe2f9\x08\x86\xd0N\
-\x0a-D\x02 r\x13\x87`\x15\xe3\xe8\x1aQ0\x14\
-\xda\xc0\xa3\x92\xc0\x98`\xd9/G*\x9bW\xb0,H\
-\xe9\xf1LU\xb8)/\xb5,\xcc\x0c\x88\xf0\xc8\xd9\xc6\
-[\x16f\x8er\xeeb\xb9\xdae\x9b\x9agp\xd6x\
-\xb9\x06\xd0C\x0e^\xc32_\xc7\x05\x06\x9c\xc4\xf6\x9f\
-?\xfe\xfd\xe2$B\x17]a\x19^Nb\x91\xfd\x98\
->n\xb7\xcbt\xfd\xf7\xd5\xe3\xc6[\xf4\xb1\x01\x91>\
-\xf3O\xd9\xe7\xa5[\x16j\x14\xa54\xea_\xdd\xd9z\
-{\x06\x98\xddxD(\x96\xf4jb\x0bq\xaf\x8a\xb9\
-\x17$\x06DW\x04l\xd9\x8b\xa3\x0f\xe7.S\xf4_\
-\x85!\x0a\x9eA\xe4\xc0\x00\x1a\x10.\xd1q\x94-8\
-\x80V\xd3\xb6\xa3lUb\x94\x91T\xb6UD\x0fw\
-\x11\xc4m\xe9\x88\xf3\x8bfM\xcdo\xe4\xf8a\xd6\x22\
-\x96\xf1@`|n\xe7\x0f\x837\x98\xf1hf\xeb[\
-\x88\xa9\xa0\xaf!\xa6\x10\xca\x19\xcb\x055\xc3R*\xe8\
-A)=_b\x80\x92\xdfb3\xc0o\xe8\xf5\x9e\x9a\
-\xd6s\x81\x13X1%\x8c'\x18\x18:q\x9epb\
-\x98\xe7\xe4\xba\xd0\xc9\x9a\x84\x1aF<\x5c\xe6\x1cb%\
-\x8d\x1a\x9f\x9ako\xe5\x84\xdc\x5c{\x8d\xd4K\xd2U\
-\xf98\xa3\xa4\xa7\xa1\xaa|\x5c\x01\xfd\xba|\xdc\x0f\xee\
-'\x94\x1f\xb2\xb1\xfa\xfal\x94\x04\xff\x85\x07F\xd7\xf4\
-x\xf6\xe9\x8f1\x05\xec\xe4 \xeb<\xa6\xe0u\x9d\xc5\
-\xd7L\x9a\x10A\xbdLhX\x84OM\xeem\x1f6\
-Y:\xff9\xdb\xdd\xe5xD\xd9\x02W\xd5\x16p\xc3\
-\x13E\x88l\xe7F\x804\x84C\x10\xd9\x16p\x10\xed\
-\x84\xa3\xe7\xe5K\x10x\xc3\xe8\xae\xbc \xc0,6\xfc\
-\xad2\x1fD\xf0x \xf7\xe1\xe1\xd9X\x86\x06Mh\
-\x91\x00U\xc3\xb2z\xc0h~\xbb\xa4\x0b\x84$@\xd6\
-?\x81\xd5eZ\xbc\x8asL-\xa3\x82(\xd6\xd9|\
-\xd79\xd6\xea\xcf\xe5\x1cs{\xbe\x9c\xf2\x9f\xd29\xfe\
-&\x9e\x1c{%\x9e\x92BA<e\x87yJ\xb0\x83\
-<u~\x83\x10\xe4\xa96\x8a\x12\xe2\x0c\xefj\xeb4\
-\x07a`\x098\xe6\x12\xc1 \x80y4\xca\xb1\x15\x91\
-\x9c0m\x90\xdd$\xd1R\xc9I,T\xc2\x158\xb6\
-\x98qg\x98p\x07\x93\xd9\xc9\xb8\x13\x9aHNE\xcb\
-\xacP\x93(0\x22\x9a\xb6\xccJ\x1f\x15\x80\x12P)\
-\x0c\xcb\xce\xfb\xfe\xa7c\x828e\x83\x22\xeb\xf9\xf6(\
-K\x1a_\x89\x81\x19n\xcb\x92@\x1a1FhK\x96\
-\xfa\xb8\x8b n\xf3Ff\xdcA\xbeB\x9a\x08\xa9\xf0\
-\xad\xcc0\x9e\xf3\xb7\xb3\x85\x9c\xfe\x11/ \x8eq\x15\
-{\xc9\xfb\x87\xd7\xe5\xbd\x93\xbd7n\xac\x8eu\xcc\x0f\
-1N\x9d\x060\xd6\xc6\xa2\xf5\x8a\x7fdH\xb5\x98\xe1\
-o\x87\xcfN\xe3\x1d\x83\xbf\xdd\x11B\xae\x9dd\x0c\x02\
-,\xdd\x8d\xe4\x8b\xea\x1c\x02AV\xac\x8f\xbb\x8e\x80\xc9\
-cv\xc0y\xd4\x8cs\xad\xa5=\xb2g\x92-\x025\
-\x16c\xa6\x96.\xbd\x13\x9a\xdaX\xc2\x84\x1f\xe7\x84\xcb\
-;xF\xb3~\xc5\xc3\x98\xa95\x1cp\xe8\xcd\xc8\x91\
-\x19g\xd9\xecfvs\xe8\x80O\xab\xa5\xe8GK\x1c\
-\xb8\xff\xc8\xd2\x99 /\xe0Kb\x95y\xc9\x19\xc1l\
-\xfct\x22\xa5\xd9l\xd1\x93\x82\xf7\xe7\xa2\x92\x90\xd4\x80\
-\x8f\xa1\x8fQJHFb\x1af\xed#l\x95ep\
-\xce_%\xc5\x02\x7f\xc7H\xb1(\xde)\x84,\x81\xb4\
-\x0a\xd5\x10?~L\xb0U\x16\xdb8\xf4\xa6\xf1\xc8Q\
--\xd4B.\xe4y\xf8\xf9k\xfcFK\x87j\x84\xf0\
-ec\xcbSS\x1c\x8d\x85\x9f\xbaw)>\xacH\x91\
-\xca\x83\xa2\xab\x16\xc0eE\xceD\x8d\xae\x98y\xc5\x1c\
-\xca\xd1\xad{\x19\xcb\xf1\x89\xc5\xd7#\xd0\xa1\xc0\x0e_\
-\x0b\xbb\xd2+\x81Q\x9e\xc1\xfc\x8a!\xfa\xf8K\xfcW\
-%\x9d=\x91tC\xc5\x0c\x8c\x13\xad\x80\x11\xbb\xbb\x8d\
-\xa5L\xa8\xa1\xd0:aHI\xd8\xb6\xb9|\xa5\xc3\xf8\
-#\x89)\xf8k\x11\x93\x96\xd5f-Zb\xda\x0e(\
-a\xe8_\x92\x96\xfa\x9b\xd22.\x13\x9e\xe4/IL\
-I_]\xcay\x8b\x9aVb])\xb5\xafK\xcc\xeb\
-)\xdeKpO\xf5\xdd\x0d\xbcJ1\xff\xbc\xcc\x9e\xde\
-\xd5\xd4\xb8I\xeb\x9d\xe1\x85\x0eg\xd7\x81\x86E\x0cZ\
-6\xdc\xe4\x9by\xb6\xa9\x9a\x94\xfbi5\x95\xa6\xbf\xb9\
--\xe2\x1d\x19\x8eZ\xb7\x93p\xfb\xf6.\x9d\xe7O\x1f\
-.X\xb7\x11\xaf\x97`\xc0\xa6\xa42R\xf4\x9a]\x90\
-\xc8\x13\xad\x89\xe5\xa6\xd7\x88\xeb!\x22\xa1\xa4\xb1Cu\
-\xe3<\x9f=\xe2e\xa6\xf8\xb18\xea\x87}\xaf\xfb\xe3\
-f\x83\x08\xab\xf49\xdb\xb4\xaf\xd64\x97o\x8c\xa9;\
-\x96\xd7s<\xc8\xf6.\x7f*\xe8\x83\x95\x9b\x8fYw\
-\x06l\xf7w\xef\xe1`\xd3\xed\x06\xcf'\xd4\xf1i\xb9\
-\x86\x0equ!\x88\xca\x1eaJ\x8cj\x99\xba\xae/\
-\xeab\x00\x01\x03t-\x1b\x9f\xf1\x15\xa2\xbf\xa2\xc7\xe5\
-<\xdb\x86\xd7\xe4\xda\xe2\x9b\x9b|\x1fn\xcfo\xfe\x0f\
-\x047~Hww0\xc2\x22]m\x0f\xa1\xacs7\
-\x89\x8fR\xb4\xec\xf2U\x06\x227\xcb\x1a\xb7\x14i\xe4\
-\x83M\x8b-\xcb\xa3\x0b\xd2\x1e/\x04\xdd\xae\xf2\x9bt\
-5H\xe3\xfbt\xbf\xbc_~\xc9\xe6\x8d\xd7\xdf\x1e\xc3\
-\xdbq\xa9\xc2\x1a\x92\xc0\xe2*\xf9\xdc=\xe3\x95\xaf\xfd\
-3\xc2Z\xda\x08\x01L\x88\xc6I\xc3\xab_\xcb\xf5\xed\
-\x1e_\xb6\xa3\xa0\xd5\xecT7=\x07\x9a\xb2\xfb\x87\xb2\
-\xb5\x91\xa2(\xfa\xbc\xdc.o\xd0g\xf7v\x08\xb8k\
-\xbc'5\xef@q7%>\xae\x09\xb5\xe46_\xaf\
-\x9eK\xb4J\xa9\xf4u\x89\x83\xdfg\xbbt\x9e\xee\xd2\
-F\xb1T\x10.h\x951\xb9\xde\xcc\x17W\xff\xfc\xf4\
-C\x1d\x8e\xccfW\xff\xce7\xbf7!\x06\x22\xa47\
-\xf9#\xf0l\x1d\x9f\xe1}\xab\xd9\x15\xea\xd9t\xf7q\
-y\x0f\x02\x83\xf7\xf8\xfe{\x7f\xbf\x02\x15W7\xb4\x90\
-\x91\xda\xcd\xa0\xc5\xb0\x9b\xac\xb8\xa7\x17\xbc\xda8\x9f\xdd\
-/\xb1\xd3\xf4_\xbb\xe5j\xf5\x13N\xe2\x85M\xe5\xa0\
-\xcb\xdd*\xfb\xe8\xe6,\x1e\xab]L\xcbmTA\x8f\
-\xb7\xcb\xebiE\x06\xf7\xe9\xb6!\xcf\xadVu\x22{\
-\x17\xaa\xf06\xa0\xd6\xa4\x92LMb\xbcz\x90\xc5\xea\
-\xb2\x22\xe3m\xcdU\x01\x0b\xc4\x85`\x8a\xa1\x01\xa7\x09\
-3`\xb3\xb1X\x8fY\xc9a\xc2\x89k\x96V\x13\xbc\
-\xd2@t\x02\xce&\x07\xbfS\xf2D\x12a\xd9e\x9b\
-5\xb1\xd4\xb7\x09\x937 \x82\xbd`\xb0\xa9\xc4\xb4\x9a\
-\x12\x0a\x91\xe4\xfb\x05P\xf0\x0ah\xfb}\xc7\x10\xbbk\
-V\x97\xae\xd9\x0b\xeb\xb7\xbbM\xfe{v\xb5\xce\xd7\x0d\
-+\x96)D\x98O\x0b\xe5\x07\xdb\xa5\xc6\xeb$\x8f\x1b\
-u\x8c\xf5\x0e\xae,\xd1ks\xaf\xbd-P\x80\xb7J\
-Y\x81\xafc)\x12\x10=\xdd\x1a*DRM`o\
-\x10\x8fL\xbc\xc78\x0c\x06\xa3\x7f\xe9\x07\xdcm\xa2\xe1\
-\xa4B\x83\xec\xd2Vi\x83[\xa2J\x14k\xec\xaa\xbf\
-+\xeen\xa5\xb0V*\xa5\xd2\xfdX7\xa7x\xef%\
-NA;\x1d(\x0f\x1e:\x1d5\xf2t\xceL#\xb4\
-\x09\xde:+\x05S\xa8\xcct3\x1b\xdaD\xaf\xd0\xdd\
-\x98\x13X\x0cg\xd6\xc2\xb4\xf29\xd5\xf4\xeeE\xa2D\
-\xd2\xb7\xd8\xa9iw\x97M\x9c\x226\xa1\xf6\xcd>\xc0\
-\xa8M\xebs\xa0\x15\xb5fD\xa5\xc6\xd0EL\xaa\xc1\
-\xa3Y\x84wh\xac\x90BF\xa0\x0b\xb8\x01\xc50)\
-:Gq\xf1\xb7\xfeX\xe0\x81\xa0\xd7-U\x8f\x06P\
-\xe2\xc21\xd4\xff\xae\xa2\xb2\x91D_B\xcb\xdd\xee\xd2\
-M7\xf1U\xb5ekX7O\xa8\xa0\xd22}>\
-6\xa1\xd4\x82\xefF,x\xcc \x1c\x9aI+\xed\x80\
-l\xbdH!Yr\xb2B\xb2\x01\x85\xe4\x0eJ\x9a\x83\
-\xb2\xeb\xbf\x96\x18\xd4H\x01\xe5pNa\xbb\x9e\xde\x96\
-\x0f\xbe\xcc\xf5g\xa0\x89\xd4\x960\xa5'\x18\xd1X\xc6\
-\x85b8A\xfd\xdc \xc4\xb0\x13\x89\xaf-\xc1\xe0p\
-\x99H\xce\x98\x97\xbe(8\x1a\x0c\x0d\xd7\x10\x13\xd5\xd7\
-G\x1cKS<\x22\x09\xa1e\x14\x9b\xc4\x80M2`\
-\xa9\xaa\xfb!Q\x5c>\xb6@U\x0fd\xef\x1a>\xa9\
-\xba\x9b\x16\xb0\xe9G&M\xcf\xa8\xc2\xf5\x11\x82\xbd\xfc\
-\xc9\xaa\xb5\xd4\x13\xf5\x17\xd7\x88MK\xc6\xfb\x17^Z\
-\x0ab\xa09|\xdf\xa6\xa5\x9eZ\xf7sj}\xe6_\
-\xfa:\xae/\xc1\xe8\x8f\x91\x80\x80V\xae\x99j\xc0\x1d\
-\x81xPIK\x84\xbbG\xa0(\xb8\x18\xcaqj\xfd\
-\xdc \xc4\x94\xe3=\x02\xc5\xc05Q*1\x10*\x8b\
-\x9eCB\x14V*\x8d\xb3\x1cM\x5c\xe1r\xd9\xbe0\
-W-H\x86G\x885b|\x1d&\xc0\x15b\x22\x84\
-\x96o\x96\xb7\xcb5F\x0a?G\x10\xc4\xe3}h\xd0\
-\xa7\xael\x0e\x96\x1b\xfd#\xa2\x10\x90+\x108\xd3\x00\
-\xdduP\x87'Ub\x0d\x07y\xf1`Z4}k\
-\xa0\xc5\xb2\x02c\x19\xf5\xc6\x03!\xae\x06\xac'n`\
-\xd0\xdb\xda\x04\x5c<\xc1<(\xa3<\xe1\x94\xf9\x03\xd6\
- o\xe2\x1a\xe6-\xb0\x1e\xad\xd9G\x7f\xbf_\xa2\x16\
-\x19d\xf9\x80\x8b\x01\x86\x84\xe7\x06\xc6\xd0Aq\x9d\xa4\
-I\x84T\x1c$\xa5\x81\xb5\x16S\x01-I\x0c*\x14\
-\xd3\x0c\x07Q|k\xfb\xc2\x91\x5c\x82\xc9\xe1\xa6h\x94\
-\xcc\xef\x07\x9f|\x02\xc3\xc7f\xf6\xba_\xbd\xc6\xc0V\
-\xbeD\xe3}\x0e\xbc\xbc3$B\xef\x8b\x9a\x99\xa2k\
-s\x87\xe22\xe4\x8a`\x01W\xd7\x1d\xa8V7\x11`\
-cA\x1b\x80\xee\x8c\xf1\xee\xac\xb1\x85\x99\x07\xa9\x11\x0a\
-\xe0\x13*\x12\xa2-'\xca\x83U\x0f\xa8n\xcb>@\
-\xad\x02\x916\xad}|o\x06\x84\xe1\xfc\xb1\xebg\x14\
-\xa8\xbf\x1a\xe4\x8d\xef\x16e\x09Q\xa8\xa8\x01\xd3\x15i\
-5\x08q\xbf\xcf\x97\xe8\x1e\xd7\x95\xe01\xcd\xe0`\x12\
-\xbc\xc9\x05\x9a\x22bx\xa1\x10q\x91C\x15%\xc8\xd3\
-\x15\xa8z\xc0\x9eE\x0fh\x8d\x1d\x22\xe1E3\xce\xd6\
-\xc2G\x80C\xe6\x8eb\x05h\xe2:Y\xaa\x08m@\
-%6\xee\xc6\xe1s\x0bB\x81h\xee\xe6w=\xb7\x8f\
-^0\xcc\x11\x83\x0d\xd3P\x8dQW\x91\x16\xac?R\
-\x89%\x96\x92\xd1\x89J\x984\xc4\xdd*?\xe8\x1a\x87\
-F6TS\xa6\xa9-G\xae?r\xe0\x16\xd8\x1a\x9c\
-\x01\xac\x1f\xc2Hk\xf5\xe5\x00oA\x88iy\xcd\x5c\
-\x16\xdc\x1c\xed\x98\x8b%(E\xc8[\x12v\xccE\x03\
-*\xff\x16\x9c\x85\x1d\x94\x8a*\xb4\xba\xb1\x8b\xec\x8d\x8d\
- T?\x8e\xaf\xa4\x01K\xc4=X3z\xb9\x1e0\
-\x07\x8e\xaf\xf0\xde\xa1i\xda\xe3~\x97\x82\xad8\x90\xa2\
-\xe0+\xb0\xa1\xd6P\xc7Wx\xcf\x19\xfcjP\x14\x10\
-\xec\x98\xf2\xb3\xfb/n\xa3DD\xfeE\x14p8]\
-\x9b\x1b'np\x8b\xcf\x0e[\x0b\xea\x18\xaa\x84\xba\xca\
-0c\xb8\x01\x9d\xe5\x01\xebN\xb8\x99\xb2\x1b\x8f\x0aT\
-\xca\x8av\x19\xb5\xf1\xdb,\xd5\xc4*$\xf0\xee\xb9q\
-y\xa5 \xa0\xc9\x15}\x7fPY\x092h\xefC\xca\
-J\xd0\xb6\xb2z\xb3\x8aoV1\xe0C\xe1\x9dd0\
-*\x96\x04\xa3\xe1\xb0KvP\xd3\x1dSO\x9a\xf5\xb4\
-\x93\xe4\x07u\x93fQ\x892\xac\x98\xdc\xa8\x1d\xbd$\
-\xad\x12\x03zII\xaeJ\xbd$\x88<Y/\x81\x8a\
-i\xa9%\x94\xdf\x90Z\x02\x17\xb9RK`\xf2\x8e\xa9\
-%\xd0n\x01\xb5\xa4\x88f\x83jIRm\x0a\xb5$\
-\xb9<I-\xb1V\xec{<\xd3dG\xe7\x01\xdf\x94\
-\xcd\x9b\xb2\x09+\x1b\xc5\x05\x16l\x9fA\xd9\x04\xc3V\
-N\xc1?\xe3\xd5;\xf1\xf2S,\x13L\x00Ye]\
-ZMi\xa2\xb9\x1cr\xab\xe0xk\xad\xc5 \xa4\xa5\
-\xa5\xc7\xce\x9cHQ\xf7\x1a\x97\x09\xee\xc1\xaa\x87Bw\
-a\x1fp|*\xc4\xa6\xb5\x8f\xef\xcd\x80\xb0\xc2\xbf\x05\
-\xaf\x8f\xa3_U\x00\xbc\xb1\xcb\x05\x19\xa9\x9d\xf3\x0c\xce\
-\x9b\xb5\x1eB\xdc\xedQ\xf9\xea\x95\xab.\x0dj.\x8e\
-70\xca\x9d\x08\xc1\x98T\x0d\xa8z(\x1cup\xf0\
-\xac\x15n.\x01\xde\x0fw\xcd\x85\xa2\xf4;8H1\
-\xbc-T|\x01t\x9b\x11\xa0g@B\x1aX\xd5\xa3\
-p\xd7]\x1f\x1a9D^\xb6\xba\x05\xb4\xf0\x1d$\xac\
-\xc4\xec\xb0oE-t5\xe2\xb0o\xc5F\xe6R\xde\
-\xd4\xda\x9bZ\x0b\xab5\xcc\xe12b[\xdf\x07rN\
-'\xca\xaa&\x81\x00Q\x18\xd1\xa5:\xaa\xf2\x07\xe0\xbd\
-\x09\xa6\x1aP\xf9\xb7\xd0E\xae\x83\xcb\x1eP\x97\xb0\xab\
-\x1a\xbb\xc8\xde\xd8\x08\x92\xaa\xf4\xa5\xa0\x17t\xf3`\xcd\
-\xe8\xe5z\x84,b<*-5M{\xdc\xefR\xa8\
-#V\x88\xbfSH\xb0C\xa6\x8b\xdc\x81*\x14\x12\x83\
-\x11!`-\x01\xc5\x9fB\x19!\xaeRN\x19\x01\x12\
-\xa7\xae\xb1p\xdb<lY)#@W\xb6L\x1cT\
-\xdb\x81\x9e\x86H\x1c\xa4\x01\xd6\x9d\x0a}\x84\xdd\x8c\x88\
-\x0aTk&\xe5\xd8Q\xbb\xc3Am$O{yg\
-\x07_\xde\x05\x93PZ\xbc\xc5uo:i\x84N\xe2\
-L\x18\xabZE\xe6/\xd5I_\x91\xa3\x077\x0c\xe4\
-\xd9\xb4^\x91\xbf1\xed\x1b\xd3\x86\xd4c\xff\x1e\xf2\xc9\
-Y/&\x82)zn\x87S\xf4\xda\xcb\xd1\x13\x0b\x82\
-Sz\xb1\xb6\xccg\x1b!\x09\xd5\x0d\xa8\xfc[\x98X\
-\xd7\x81G%\x1a\xab\x1b\xbb\xc8\xde\xd8\x08\xaa=d\x97\
-\x8c\xa6\x1e\xac\x19\xbdX\x0f\x87\xf0\xc5\xd9=C\xb9\xd6\
-M{\xdc\xefR\x98XR\xe4.\x9c\x89\xd5\xda\x15\xb6\
-\xe2\xf0\xe5f\xa4\x95\xda\xc8\x0aP\xfc)L,\xe2\xd2\
-\x221/\xf15\x02\xc7\xab*\x95\xbf_\x22\x8b\xda\xdd\
-\xd7\xeeB\xb7k\x13\xf5f\xe0\xaf\x92\xc2\x07\xd6}\x0a\
-\x03\x0b\xbd\xa4U\x91C\xc5o\x06,\x87\x8eZ\x1dF\
-e\xe7%\x97\xcc\xa8\xaah\xb7\xfe\x08\x1c\xc9\x94\xb4\x1c\
-\x0e\x22\x11\xca\x0a\xad\xcd\xb1w\xe9My\x5c>\xcfP\
-\xc7\x81\xe6\x9am\xb7\xdbf\x09\xcd{Z\xdd\xbc\xbcu\
-|$q\xdd\xd2\xc2\xb9P\x86R\x05\x8bp\x8c\xc4A\
-\xf1I|w\x817\x93\xf1\x8b\x94\xc1\xe9\xd0x1Y\
-BDH\xf1\xd5\xa5\xa4R\x15@+1N\xa5\xa8\xaf\
-\x8cf\x10Xb\xc8\xc3\xb8\x9d\xa8DP-\x84F\xff\
-M\x80<\xc0,\x16B1x\x8c\x98\x04v\xc0\xea\x0d\
-\x80 sB\x9c\x86\xdf.\x0aS\xe1\xfb\x7f\x98\x07\x5c\
-Bf\xe0\x1c\x89A*\xd3\xc40\xae\x15G\x98b\xc4\
-h\x80a%\x19\x84\x7f\x1cdY\xc33\x9c8,\x97\
-\x09\xbcH\x8dN\x9d\x02\xd7S\xe2\xeb}\xd0O\x04\x1c\
-8\x15\xdc\xab\xf7\x0a}\xd8\xdd\xc1;\xe0\xa3\x22-\xaf\
-n|\xbd\xcef\xbb|\x13\xcf\x1e7\x9f\xd3\xdd\xe3&\
-\xc3j\x96\xfa,\x8f\x96C\x94\x89\x00\xe9\x8a\x1c\xac\xb5\
-\x04\xc3eW\xa0\xa35a\x9d\x82\x07\x8dE\xdb\x94\x03\
-J}\xff\xd4+\xe2\xf1\xaax\x8e\x95\xf1\xc8@\x1dO\
-\xa8\x90\xa7\xc6\x8f\xea\x81\xab\xc6\x0e\xae7p\xd9R\x0f\
-\xdb^\xc2\x81z\x86N\xcd\xd2P\xb5S\xab\x92\xa1\x7f\
-\x11\xb7U\xc9\xd0\xbf\xbd\xdb(\x5cJ\xba|\xe1\x05\xe5\
-L\x00[\xd2\x81\x17\x1e\x9c\x8e+\x08\x1b*p\x08\x0a\
-x\xbf<\xed%\xabc\xe3R\x06\x0d5\x18\x19K\xc1\
-\xb1\xf4\x1f:\xba\xc0\x91\xff\x059<X\x7f\x8b_\xf8\
- \xc1\x0c\x1b\x8b)xP\xffL\xd5\xd7\xd1J\xdd\xdf\
-\xaa\xe7\xe5\xb6\xfe\xaa\xd6\x1e#@$JE\xf3\xc5\x89\
-\xad\xca5<\x1c\x5c\x91\x17\xef\xed\xcb\xbb\x1c\xde7\x14\
-U\xf5dE\xa5\x99\xf5\xbe9\xbc,A\xe3xC\x07\
-\x1c\xc4\xce\xf7\x8c\xc2D\x9c\x8a^AP\xb34C\xdd\
-/'\xd5O\xc1\xac\xdf-\x88\xfb\x12\x82\x01\xdel\xbe\
-\xa4\xc2\xdb\x8dGJ\xfc\x1fr\x00\x19\xe9\xc4\xbb5\xd4\
-\xa7\x8cbF\x02qN\x9f\xbe\xb7M\xeb\x15\xef\xb4\xea\
-\xf2\xacG\x94\xfa\xff\x9aR\x14\xcez-{,\xbf\xeb\
-P\xfd\xd9\xbf\x80\x13\xdc\xefs\xf0\x8a\x0e\x0c\xa5\xf1k\
-e\x8c\x7f3\xf7\xf0\xd4\x07W\xeb\xedm\xe0\x08K\x1a\
-\xb2\x8a\x84\xf4d\x1a\x1e8\xb5!f\xafk\x14{\xcb\
-\xd1\xc6\x9d(?\xc0\xecAr\x1dbw\x8d\xb6\x16\xa8\
-\xc8Nb\xf7\x01\x83q\x88\xdd\xf9Bff\xde\xa6\x15\
-l\xc5\x82\xc2U\xaa\xfc\x16,\xf89.\x00cg\x0c\
-\xb85Xe2\xda\x1a\x94[\xed\xb1|\x9f0\x15-\
-\x9d\xda\xa3\xbe\xea\x08\x10\xfe\xe5\x1c\x7fN\x8de9?\
-\xf9\x08\x83\x04\xe5r\x90\xa0\xc7TX\x15!LP\x1e\
-\x8a\xe8`@\x97\x9d\xb40{\xdaICH\xd6\xa5\x9f\
-\x93\x0d\x0d\xff\x8c \xb9Sn\x1d+\xf3\xdc\x9c\xd9\xa1\
-\x83\xee\x9eih\x98\x16{\xf5\xe4\xb4\xbf\xc8fK\x82\
-\x9e\x87\x96\x82\x8f\xa2\xe5\xb1s=\x85\x19\xe2\xf3r\x83\
-\xd0'r\x83w_\xec(7t\x0e\xe6\x00+\xc4\x95\
-Kg\x0er\x83\x872\x86!\x0e\x0a\xfe O\xd8\xf3\
-PT\xd2\xaf\xe1\x89\xb8\xc3\x14\xce\x04^\xe3\xb5\xb3\x8f\
-\xef\xfe\x1f2\x91g\xd1\x9do\x00\x00\
-\x00\x00\x10\xb4\
-\x1f\
-\x8b\x08\x08\xd3\x9cBb\x00\x03Gnome-f\
-s-directory.svg\x00\
-\xd5Z\xedn\x1bG\x96\xfd\xef\xa7h\xd0X$A\xc8\
-f}\x7fp$\x0f\x12\x09\xde\x0d`\xef\x06\x1b\x07\xb3\
-\x98?\x03\x9al\xda\x84)R\xa0([\xca\xab\xed\x8f\
-}\xa4}\x85=\xe7\x16I\x91R\xb7V\x1e\xc7\xd9Y\
-F1\xbb\xba\xabnU\x9d\xba\x1f\xe7\xde\xe6\xc9\x9fo\
-.\x16\xd5\xc7f}5_-O{\xbaV\xbd\xaaY\
-NV\xd3\xf9\xf2\xddi\xef\xd77/\x07\xa9W]m\
-\xc6\xcb\xe9x\xb1Z6\xa7\xbd\xe5\xaa\xf7\xe7\x17\xcfN\
-\xae>\xbe\xab0ry5\xba\x19_\xbe~}\xda{\
-\xbf\xd9\x5c\x8e\x86\xc3\xe5U=\x9e\xae\xde6\xf5du\
-1\xc4\xa3!$\x0e/.\x86\xbd\xbb\xde\x8f\xf7\xddu\
-\xbc\x9c\xce\xda;\xe2\x01:\xda;\x89\xa7=y8\xc2\
-\xf5E\xb3\x19\xef\x1fL'{\x01\x97\xd7\xebE\xbdZ\
-\xbf\x1bN'\xc3f\xd1\x5c4\xcb\xcd\x15\x84\xe8}\xdf\
-\xc9]\xdf\xc9\xba\x19o\xe6\x1f\x1b\xccu\xb1\xc2\xcc\x1c\
-\xb6\xbcz\xbe\xeb\xb9>X\xd7\xa7O\x9f\xeaOVz\
-\xe8\x9c\xf3P\x99\xa11\x03\xf4\x18\x5c\xdd.7\xe3\x9b\
-\xc1\xc18\x00\xd66\xce(\xa5\x86x\xb6\xed\xf6\x84.\
-\xa3\x9b\xc5|\xf9\xa1s\x0d\xf2\xb4W}\x9aO7\xef\
-O{.]nz\xd5\xfbf\xfe\xee\xfdf\xd7\xfa8\
-o>\xfd\xb8\x02l\xaaR\x95K\xf8\xe3\x09\xdf.p\
-\xb8+(\xc2l\xb1\xfa4\xfa8\xbf\x9a\xbf]4\x7f\
-j\x96c|\x0d\xde\x8e'\x1f\xde\xadW\xd7\xcb\xe9h\
-\xd9|\xaa\x0e\x06\xce\xa7\xa7=\xac\xcd\xf3\xfa@\x8bt\
-\xef\xc5\x09\x17\xb2\xdbU\xaf\xda\xdc^b\x82Ms\xb3\
-\x19N\xae\xaez\xd5\xbaY`$\xa7\xbdz\xdf4\x9b\
-\x22i:^\x7f\x18\x5c\xac\xa6\xcd`r}\xb5Y]\
-\x0cd3\xc3/\x94\xf5\xaeY6\xeb\xf1b/Lz\
-\xdeI[\x8c\xa9\xea\xcd\xf2\xa1\xdc\xd6%\xc9\xe8/\x10\
-\xb3\x14\xed\xda\x8byVU'\xd3fvUz\xe1\x22\
-\x04\xd7\xe3]\xdc_\x8f\xa7\xf3\xf1\xe2\x9f\xf9\x05\x8d\xad\
-\xdem/~]\xce7\x98\xf2\xfa\xaaY\xffr9\x9e\
-4\xff\xb6\xfc\xf5\xaa\xe9\xed\x1f\xbfY\x8f\x97W\xb3\xd5\
-\xfa\xe2\xb4w1\xde\xac\xe77\xdf\xaa\xdaF\x97\xfb\x8a\
-\xff\xe1\xd2\xf7\xb5\xabs\xf6\xb9\xaf\xfdw\xbdjv\x0b\
-\xcd\x88\xb5\xca\x1ag8\x83^\xb8\x5cg\xe5,p=\
-\xedYU\xabdC\xaf\x9a\x1c\xf6\x9a\x1c\xf6\xe2\xc2\xff\
-\xe3\xf5\xab\x9f\xce\xff\xa6\xfd\xdf\xb6K\xc7\xe2\x01\xd6e\
-Q\x0f\x5cx\xef\xf7J\xc6\xf6`\xb2Z\xac\xd6\xa3\xe7\
-\xc9\x9f\xfd\xf0\xf2e\xafZ\xcdfW\x0d4T\x15D\
-\xda\x04\x84V\x01J\xd9\xf3\x1f\xf2\x9d\x00\xbd\x13p2\
-<Fo{\x17:\xd0\x8c\xd7{Ho\x0d6\xa2\xea\
-l\x02\xc4\xdf\xa0am\x1d\x95\xd7\xbd\xeaV\x9f\xf6\x0c\
-\xb6h\x0c\xa4\xdf\xe8\x83'\xff\xcb1\x1c\xc0\x11:\xe1\
-\x08\xa6u7\xd6\xe6\xfc48\x82}\x92\x80\x038\x8e\
-w\xde\x0d\x076\xedc2[8B\x9dB\xde\xa2\xe1\
-j\xaf\xa3.h8[\x07\x1d\xcd\xe7\xa0\x11\xbb\xd1\xc8\
-_\x88FT\x1d\xca\xc1\xcf\xdf\x8d\xc6c\x06\x95}\xb4\
-0&\x93r\x7fP\xbe\xb6\xf7`Z\xd1Z\xd3\x0f\xb6\
-\xce:\xd0\xbe\x08\xea\x80\xa6\x93\xa2+\xa8j_\x07o\
-m\x81\xf5\xe0\x11[\xda\xd4^}\x16\xae\xa9\x13\xd7\x98\
-\xda\x8dN>O\xc2\xb5\xfd`\xbc|\xfe!p5\x88\
-5N\xdb\x82\xab\x89\xb57z\x87\xab7\xe8\x99\xb6\xd6\
-;p\xb5\x11\xa3y:\xae\xb9\x13\xd7\xd4\xee\x8b^\xca\
-\xe7)\xb8\xa6\xd8* \xe7\xb3\xb3\xcf\xb1\xde?.>\
-\xd8\x88\x1bA\x97\xf8\xa0Cm\xbd\x0e\x12\x1f\x10\x05\x9c\
-f\xf0\x9f\x1c\xf6\x9a\x1c\xf6\xba\x83\xd4\xa8NH\xb3\xfb\
-\xc2\xf8\x90\xdb\x03\xcc\xe7\xc6\x87\xdf\x13R\xed\xa8\xc3\x88\
-\x19\xa6/_Z\xd0\xd5\x80\xd7\xd6\x088\xa1\xaf\xc5\xf2\
-\xed\x16c\x9dj\xc5\xb8@\x88m\xaauH\x82p\x86\
-\x19\x04\xfa\xe3\xc9A\x9f\xc9A\x9f\x03|u\x17\xbeA\
-\xb5\x07\x9c\xfb\x1a\xd7\x89oPO\x0b8\xaa\xf6\xdd\x22\
-\xda\xcf\xd8\xda\x10:\xb4\xfe)!\xfcQo\x92U\xe4\
-\x19h\x1b\x5c\x7f\xffU\xee:\x040\xeb\xfa\xbe\xf6!\
-\xc4\xad;\xd1\x1a\x01\x9f\xc6Io\x92\xeb\x10L(\xce\
-\x84\x06a\xb2)\xbed\xf7\xe0\xc9\xae\xc4\x98\xces\xd1\
-_H\x04\x82\xee8\x97\x1f\xf3\xf9\xf1\xb9(\xefB\xb7\
-\x94\xf6\xa3\x09\xeeG},\xc5:\x1b\xbb\xa5t\x90<\
-}\xa6\x8e\xa5\x04\x15\xbb\xd5D\xb7{\xd7l\xcf\xeei\
-Z\xb2\x8f\x08\xf9}<\xecW\xd45\xeb\x8a)\xdf\x14\
-\xce\x85\xe3\xd9\xb2Nx\x87h}*\xba\x86\x86\x93\xd3\
-y\xba\xb2\xd9Ne3\xed\xba\xf2\xe4\xb8\x15L\x87\x9a\
-\x84\x1f\xed\x17\xb2N\xe7jg\xdd\x16\x0e\x04\x15\x13\xf7\
-p0\xcf\x08\xb1\xc0\x01\x0e\x1a]\xf8,\xdbs\x9dp\
-\xd8v\xdb{:\x1c\xb6\x1d\xcf/T\xb2\xdb\x92\x86\x84\
-`\xd3\x16\x0e\x0bJ\xb8c\xe1\xf0D)\xee\xd8\x22c\
-l\xd4\x9f\x93\x93\x98\xce\x14-\xd8/d\xe1\xc1u\xb1\
-\xf0\x10\xce\xce\xbe,'\x09\xc8\xbd\xa8\x107%_\xf3\
-\x8a\xd4V\x92\x92\xfd\x13\xc2aj\xa7\xec\xe7\x90<\xd3\
-\x99\x94\x04\xd7\xeeA\x9eL\x9e\x83kg\xdf_H\x9e\
-oKV\x16\x5c\x8e\xfb\x14M;xB\x81\x03\xd8\x04\
-\x13\xb7\x9c\xd7\xe9\xda;\x97?\x07\x8e\xce\x5c\x22t$\
-\xf0g\xfe\xa5z\x9avt$\xf0\xfa<\xba\xf3v\x82\
-\xf6\x10\x8e\x93!+$r\xc5R\xdft\xbc\x19\xcb\x04\
-\xbb\x86\xc7n\xb7\xa3o\xb0\xc1\x0f\x0dF\xbdm\xde\xcd\
-\x97\xa7\xdf\xfc\xf7\x7f\xfe\xd77\xec\xfb\xcd_\xfck\xf5\
-\xfa\xf2\xacy?\xff\x97\xdf\xd6\xcd/\xbf\xfd\xeb\x9b\xc9\
-o\x1f&y\xfa\xcd\xc9p?\xa6H\x18\xdd\x5c\x5cR\
-r%W\x9b\x0fD\xe9\xe7j\xb3Z->\xcc7\x95\
-\xad\xd5\xc0\xe4~5[\x8f/\x9aO\xab\xf5\x87J\xd7\
-\xe1\x0e\xbd\xdd\x92v7\xc8-\xa7\xb3\xd1\xbf\x9f\xbf\xbc\
-\xbb\xb3\xbdw\xde\x5cM\xd6\xf3\xcb\xcd|\xb5\xac\xd8\x1e\
-\xbf]]\x03\x89\xeb\xeb\xf9t\xa4\xa7\xde\x197\x9e\x0d\
-\xdeNfa\xe0&6\x0f\x92J\xb3\x81\x091\x1b\x03\
-\xcd\x9fNL\xefP\x22d^B\xc6\xcf\xeb\xd5\xf4z\
-\xd2\xac_<\xfb\x81\xc5\xd1\xea\xe7\xf3\x97\xd5b\xfev\
-=^\xdfV\xbeV\xeadx\xdc\xeb`\xf8\xf0\xde\x9a\
-~\xff\xf5\x0e\xff_\x88\xbc\x87\xea\xcd\xf8rt\xc6\xda\
-ps\x8e\xff_<3H-\x06\xf8\xd3\xea\x8d2#\
-\xfc\xe9\xf0=/\x00\xed\xfd\xae\x0f\xe4\xbc^M\xe7\xb3\
-\xdb\xbd\x1cG9&\xbfQi\xe4\xf3\xc8\xc5\xbf\x16\x11\
-\x87\xbd\xda\x97\xb2Z\xbf\x816\xee\xce\xf8\xa7\xc5\xe2\xfa\
-j\xb3\xe6\xedJ\x83\xf0\x1d,d\xd7\xf1\xe1J\xb6j\
-z\xb8\x16=\xd0\xe9\x8dN#\xe7F\xda|\xaf\xf4~\
-O\xc7\x9d\xffP\x95y\xb8\xf4\xd7\xafG\xe7\xab\xc95\
-k\xf9?\x9d\xbfx&\xa2&j2V\xd3\x94\x06S\
-;U\x037m\xdc \xa5\xd9\xdb\x81\x8fa\x12\xa6!\
-+\xedg\xb2\x95{\x83\xff/\xb72\x9d\x8c\xc8$\xc7\
-p;\xf3\x8b\xf1\xbb\x86\xa5\xfe\xefo.\x16\xf0uw\
-O\xee\x8f\xd8\xcc7\x8b{Z\xb1]\xde\x0f\x8b\xcd\xfd\
-\xfb\xdb'\x8b9\x8b\xd5\xa3R\xa7\xbe\x19\xc0\x93\x8e\xaf\
-\x17\x1b,g\xb6ZL\x9b\xf5@\xd7\xe3y\xd9\xfeb\
-\xfe@\xf4\xb0U\xb6\xac\xf1\xc1Z\x1e\xc7p2\x19\xfd\
-\x85\xde\xf2\x00\xbbnH>\x03\x91\xdb\xcbFd\xae\x9b\
-\xab\xd5\xf5z\xd2\xb4\xbe\xfc\x99N.\xe6\xec9\xfce\
-3_,~\xa2\xf4c\xd7q\x00\xef\xb1K\x19n\xd7\
-}\xe0\xcf\x87\xf7\x1c\xfa\xc9\xf0\xd8\xe9C\xd3v!\xe4\
-~Pj\x96\x88D\x9f\x8eC\xce\xf1\xf0\x93\xcb\xf1\xe6\
-\xbd\x047^x\x16\x9eq\xfd\xbar\x11\x09\x81\xef\x93\
-\x08'[\x9d\xb1m\xd9\xf2\x99\x97\xca%6\x5c6\x95\
-\x033\xca\xd2\xd1\x9bP\xbd\xaa@\x0d\xac\xc5S_\xdb\
-\x14+\x9b\xea\x94\xa4\xd0\x03)\x93\x8au\x0a+\xe5\x0a\
-\xe3\x22[\x1as\xe0\xcb\x85\xcc\x96\x0d\x96\xad\xa0\xa5\xa5\
-s\x92D\xc7\xb3\xe1\x9cd=F\x07\xb6B\x96\x8e:\
-\x99J\xf5U50`d.\xf4-\xdf\x1b\xa0\xe5 \
-7\xa3eM\x92)\x95T\xf9Tp\xd22\xa5\xe6\xa7\
-\xf5\xc3\x96\xf1\xa6\x0f\x05M\xd6V\xfc\x8aX\xaa\xad5\
-\xa5\xb0\x0e\x8d\xa5\x1al'W\x8bj\x80\x1c+\xb1\xd0\
-\x12\xb1r\xd9W\xd2,(jm8\x12I\x16\x1a0\
-R,\x06`\xe5\xbe\xc6\x0c\xa6\xec\x83\xe9\x9aOe\x1b\
-\xc9\xe2\x895z\xd7@g\xc8cyL\x03h\xac\xae\
-\x14st\xe2\xb5e}\xc7\xc5\x88\xe9\xb1(\xaf\xfb\xd8\
-u\x8a\x06\xd3\xb3c.\xc9 \xafC`i3x\x5c\
-k'\xc5\xa0\x0c\xd2\xa0\x95\xc3d\x11\xd8\x02,c\xfa\
-,\x0e\xe9\x8ae\xce\xd8\xc7\xe1\xe1|0Hy\x8aI\
-\xba\xe2LY\xc48\x5cK\xd9\xae6F\xe6\xe6\x8e<\
-\x93M\xa7\xadLn\x00}9\xd9J\x8eR\x8eF\xc6\
-\x05-Gh\x83\x915\xcaYc\xa9l\x18[\xc6H\
-\xc3\x16\x01\xb2g\x9dd\x8cJl\xec\x94\x85\xd7N\x19\
-\xd1\x15\xcfU@\xa1(\x1b\x99\x09\x92\xb6\x02A\xf4\xa5\
-o\xd8\xe2\x81\x86\x17duY\x1f\x08|\xf5\xdb\xdd;\
-HX\x04lt\x84\x11\xdb\xd7c\xe0\xab\xfbW\x98Z\
-\xa9\x7f\xda\xbf\xdd,\x8d\xcd]2.\x97\x0bD\xa7o\
-\xcb\xe2d\x8f\x91EL\x1a\x12\xe4x\xcf\x14\x93/\x02\
-G\xef\xd7\xcd\xec\xb4\xf7|o]\xb7$\xaf\xd5\xcd\x9e\
-\xc2\xfe\xbd\xd3\x22I\xee\x8b\xda\x99\xef\xb6\xe2v\xa2[\
-\xa7\xdd/\xccn\xa7=\xb6\xfb\xa0vv\xefa\xce\xb1\
-o,\xad\xb82\x1a\x87\x0c\xe3\x0e\xb4{Qs\x9b\xad\
-T\x19E\x99C\xa4\xa6\x89U!\x0d\xa15\xe4\x80\xb3\
-Q5,WC\xb3T\xd1\x0f\xda\x18\x8fO\x0e4Q\
-\x8b#\xf5\x01\xb1\xaaOS\xe6\x10\x9d\xa0\x81b{*\
-%\x19d\xb7eM\xf6\xf4\xa9\xa8\x81\xa5^\x86r\xce\
-\x1e6z\xac\x06i\xab\x06\xb6\xa8\x81;P\x03\x95\x8a\
-\x1e\xc4\xa2\x07\xa6\xb8\x1e\xd1\x0a\x9d\xad\xd8e\xd1T\x93\
-r\xd9\x984|8P\x98\x19<\xf9\x08>\xfe\xdb\xe7\
-\xfb\xb7\x90\xdf\xb5c\x19\x05\xcb\x0b\xa2\xe7\x89\x1e\x5c\xa7\
-\x98\xc6\x1d*\xc7\xdb\xe5&\xf2^\x97\x1f\x991t\xcc\
-\xc8<}7\xa3\xd6\x813fG\x9f\x91\xbdT\x81\x91\
-\x9eqJ\xc3ma\xca\x88\x19C\xe6\xb5g\xfa\xdfj\
-\x14\xfeO\x0ff\x8f]\xb3\xfb\xdd\xec\x16gJ\x8f\x96\
-\xe1\x85'\xf4\x83F\xd9b\xff\x96\x8e\x10\xbe\x8b\xdeH\
-\x9cb\xa23\xf2\x86g8\x88\xf0/\x121B\xdc\x06\
-\x09\x06\x02\x19ME0}\x0e\xa5\x0bC\xff>\x87\x1a\
-\x8c\x82\xf3\x83\x17\xed\x07b\x87Ae\xae2\x15\xbb\x17\
-\xbfc*v\xd7\xdc5\xe7z\xc5\xd8\x95\xe1F4r\
-(\xf8\x06\x845\xa2\x02\x8c\xe8\x98\x13\x9f\xf2Xr\xad\
-\xb1\x10\x046\xc41\xc4/]\xfd\xf5\xf7\xf7\x1a\xb6h\
-1\x1c\xeb\x81\xd7\x88\xa1\xcd|\x89\xef\x03\xafq|\x04\
-\xc9\xde\x1d\x81\x92\x97Y)\x84\x7f\xdc#\xd09\x13r\
-\x12\x06a\x16>h\x80n\x8d\x80\x9e\x10w\x12\x19\x06\
-}\x11=LDh\xf4\x07g\xf0@1S\x87b\xa6\
-\x9dY\xc0\x04\xb4\xc3\xba\x93\x98\xf4\xa4Dz\xba\xae\xe4\
-\xe9^\x8c\xf1\x8c\x8c\x8e\xfbc\x14A\x80Sa\xb7\xbf\
-\xc8\xfd\x95 \x9b<\xa31Eh\x81k C+v\
-\xf7\xc5\xb0\x84\x00\xc1Y\xfa\xc8\xfdY+\xcc\x89\xf88\
-\xec\xcf%aK|\xbbH\xf3w\xdc\x9fC\xd0O\xc2\
-S^q\xba\x94\x03\xcf\x04\xee\xea\x8cM\xc6Y\xa0\x0a\
-M\x95\xf7\x8f\x89\xab\x84L\x83\xa5d\x84\x7f\x09\xda\xf7\
-py\x9e\xf3d2\x9b\xb5\xe2\x91w\xe4\x0e\xa2\xe1\x04\
-!@c\xcf2\x93Q\xf0\xf9\x9c%$\xde7I\xa6\
-\xf4r\xf0\x11\x94\xe3\x151\x8c`r\xc0\xd0\xf9\x02\xa1\
-&WpYh\x06:b\xffF\xfc\xb3\xc1\xe6aA\
-G\x0aR\x00Dg\xd2\x0b\x1c-;\x97*\xb6!5\
-)\x9c!\x08\x0c@%\xc3\x87i>\xcc\x05?07\
-\xe0\x17\x9c\x95\xf0\x04\xc8`\xa1Z\xf4\xc3$\x9ah\x06\
-izD?r\x87~\xf0E\x8b\xe8\x87\xf5\x0c\x03|\
-O\x96\x0c\xc9\x84e\xc9\x5c4\x16\xb3\x04x\x08iD\
-(K\xc6-\xc7\x86\x0d\xdc 8\x22N>\x80\x22\xc6\
-\xaf\x7f\xd2\x85u\xa2\x1f\xc4\x88\x83\xc5\xca\x10\xb5X\x8c\
-\xd4<\x1e\x1fM\xa1\xb2\x95\xce\xd4l\xe1\xae.\xb6\xba\
-wW\xdc\xfb\xf3\x99|\xda\xd1\xc9;tx~0X\
-\xb1c\x9e\xe3=\xc6m\xb6\x8c;\x09\xe3\xe6\x91\xa1k\
-\xc0\xfc\x08h\x1a\x86\xc4\x16\xf5\x03\xe7\x0a\x16\xf1\xa0\x05\
-'\x8b\xf4@\xc3\x17\xe0\xc8\xa3O2\x91\x05\xd2JK\
-\xbcT\xd4>[;\x1b\xd9J\xa2\x13\x90\x01?\xc4`\
-\xeay\x06\xc4\xd2A\x10\xae-\x14\x02\xb2\xd5VG\xef\
-\xd1m't{w\xfd8\xdb\xb6ml[\x1f\xb1m\
-\xdf\xca\xb6\x93\x90mq)\xb0\x02\x92mK\xb2\x8d)\
-\xee\xc8\xb69 \xdbF\xc8v\xea&\xdb\xae\x90mw\
-L\xb6\xedC\xb2]\x88h\xa0\x15\x16\xae\x8d\x14\xaa\x92\
-\xa4I\x88\xb3P\x02\x9dDKBv\x845\x96\xf4\xcc\
-\x8aqm\xf33{\x94\x9f\xb9\xa3\xfcL\x17;-\xe9\
-Y>L\xcf\xf2Qz\xe6w\xe9Y7\x9b1\xaa\xdd\
-,\x83R;\xc5CL(\xc9c\x14\x8e\xdf\x92=\x1e\
-\xaf\xce\x1c\xae\xae-y\xf4\xf7\x92G\x98\x94\x11,\x18\
-\xd3<\xb3<\xce\x07\x97\xb7\xa3\xbb_\xc5\xc7aP\x9d\
-\x09s\x86\x86\xf8V\xfb\xd4\xad\xc8\xe8\x1dK\x87If\
-/\xf6\x00\x05\x05\x99I\xf2\x92\xdf\xd0\x86\xa0u\x88\xc2\
-\xe4\x92\x89\xd1U3\xec\xea\x82\xa1\xa5\x85\xc9\xef.\xb0\
-O\xac\x03^\xd4I#\xe7\xd4\x92\xd3\xc2\x1fIJK\
-t\xa1\x86x\xa4%\x95df\x9c\xe9wH\xa4\x8bu\
-\xdc\x19\x87\xde\xba\xb2\x80\xb5\xc0\xb6aQx\x0e\xd5\xc5\
-J}\x9f6\x9aJ\x8d\x00\x9a\xc4J\x81~,\xb0\x1b\
-\xdd\xa1!f\x17\xc8\xa8\xb7\x9a\xf6n\x8d\x13\xb7\x10\xc5\
-\xb38\xfaQ\xfe\xa0\xb0/o\xae\x98\xf1\x1a#\xfe\xdd\
-f#\x09\x8a5\x0c\xf3\xd6\x97\xd4\x11\x81\x86G\x8bt\
-\x16\xff\x92\x1e\xc2\xf9\x821\xd7\xd9\xd0a\x04\xc5s.\
-\xe0\x0cv\xe8\xf0\xc7|\xe5t\x09:\xdcr\x12\x06\xe0\
-9Lr\x09#\x19\xc9B\x14\x93\xa9\xdan6\xc9C\
-\xa4\xaf\x96\x22\x83\x22?+\x13\x0e\xca\x8c\x03N\x99\x1e\
-\xb3\x1c\xd3\x85K\xda\xd1@@\x00?\x98%\xbd0\xa2\
-+L\xe5J\x86\xa4%\xef\x22\x8da:G\xf7\xa8x\
-\xe9%\xb3\x8b\xc2\x88\xb0\x0fF\x8f\xac\xa9\xb9\x81{c\
-F\xa1\x99\xa9\x90\xd616{\xe6- \xfa\xec\x17\x94\
-(\x1e\x9c\xbd\xc4\x1cdw\xc0=\x1b)\x12\xc0\xbf\xa0\
-c\x8c\xc2\x908S\x02\xdc\xd8\xb2\xc7\x13\x83FrV\
-\x042\xc2\xd1\xc0\x8b\xddFU\x0c\x5cf\xabM>n\
-\xb4YLz\x90\xb0\x18\xdb\x05S\xde\xaa\x0f\x0c`\x1b\
-:\x02\x9d3+<\xd0\x1emS\x091\xa4\x04^\x5c\
-;\x0e\x93\xe6\x16$[\x04mB\xf2D{S\xe4{\
-8X6r\xa1R5\xa9\x0b6o\xa9\xfe\xcc\xa4i\
-\x898M\xe8\xbf\x96\xc8\x94@\xadZ\xb5I\x17m\x8a\
-$\x97\x89>\xc4\xe7c\x1d|%\x18\x97\xd0\x19\xc5\xb6\
-\x99R\x8am\xe7b\xdbZK,5\xce\x1co\xed>\
-G\xec\x8e\xfa\xc1\xaa\xbd\x0aYn%q\x01\xe2\xaf2\
-Uhg1$\x1e\xf87Gz<\xe7\xb71\x96a\
-\x95\xac\x1a\x9e\x80!\xdb\x98\x5c\xd4\x8e\x8b%\xa7\x82\xd3\
-\xa0\xcd\x97@h\xa8\x9f\x06X{:\x08Q\xd6H\x92\
-c\xb9IM\xd51)\x14\x85\xd5\xb1\x14\x8e8\x83)\
-\xf1I\xea\x02\xb6D\x1dV\x94\xc4\xd0@\xc0%\xdd\xf7\
-\xf6\xbe\xf5<\xba\xe5\xb8\xf3&q\xc7?\x22]\x01Z\
-\xe2L\xa2\xff\xa3\xc8/\x09%\xd3S0J\xab\xda\xf3\
-r\xfbP\xcd]\x87\x9a\xbb]\xfa\xe3\x88L\x9f?\xb8\
-U\xe2\xbd9E\x99a\xeb\x8e\xa4<\x93K\xe8\x8e\xe4\
-0\x11\xfa5(K\xdb\xd1r-\xf5>J\x09f\xcb\
-\xad\xb6Q\xde\x89u\x22K\x90m\xc4\x12c\x8d\x94\x1a\
-t\xa1OY<\x1e\x94(J\xadH~z\xa9AZ\
-\x19o\x09\x18l-}\xdd\xb4\x8c\xc8\xb2\xa0\x09\xad\xc2\
-\xee\xdb\x91\x8d\xf23^\xf3\x10\xe0\x8eBO\xf0\xe6\x0e\
-`\xfe\x84\x94\x9a\xab\xc4\xa9s\xaa2\xd3vWq\xbb\
-+b\xe2\x85\x85\x96\x1c\x5c\x09O,+\x1cl76\
-\xd8\xee\x8c\xd5\xbdR\xd2\x84\xd1\x0ddH\xbf\x8c\x97\xb8\
-\x11\xa5\x1c\xad\xc4\x07\xd1\xe3\x84,X\xc2\xb3\xc4\xe0\x91\
-\xfd\xe3\x9ea\x5c\x93$\xba\x92\xdf\xfbjj\xb0\xda\x9d\
-\xdfW\xca\xf0\x095\xbd\xe5\x80?'y\xb2\x12\x1f\x14\
-\x97V\x8b\xdbw\xabe\x81\xb9\x5c\x07o{\xd5\xe5j\
-\xbe\xe4\xcf\x0a\x1cy\x89!{\x80\xbb\x00EL\xf0\x0e\
-V8\x1e\xdf6DV\xb6\x09\x8b\xa6#\xa1\x1a::\
-o[\xdd\xf3\x07\x08\xbb\xd3q~dJVDwS\
-\x92\x88\x82xB\xaeC\x98\xb6\xf0l6\xf4\x1d\xcf\xc0\
-\xc9\xfb\x0e\xe4\x1c\xaeT\xac\xbbcvG\x91\x22\x04}\
-\xc7v5\x18\xbcEz`K\xf0\xd3z[\xe1\xad\x06\
-\xfcU2\xcf\xa1\x10af`\xd8q\xa9\x93\x07z\xc5\
-\xe8\x8bGQN\x18X\x96\xc3@\xdcU\xb4QO\x13\
-9nt\xbb\xc7\x13\xbe\x06{\xf1?\xc6\xc8&\x02\xb0\
-5\x00\x00\
-\x00\x001:\
-\x1f\
-\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xec}ms\x1bG\x92\
-\xe6\xe7\x9d_\xc1\xd3|\x19E\x00\xc5|\x7f\xd1\x8cw\
-c\xd6\xde\x99\xd8\x08O\xec\xc6\xcd\xee\xde\xde'\x07\x04\
-\x822ohRGR~\x99_\x7f\xdd\x00\xc9j\x08\
-j4\x80\x06d\xc9g\x94)\x03\xd5\xd9Y\x95Oe\
-eeeWU\xff\xe1\x9f~\xfc\xee\xfa\xec\xfb\xc5\xdd\
-\xfd\xd5\xed\xcd\x17/\xb0\xc0\x8b\xb3\xc5\xcd\xfc\xf6\xe2\xea\
-\xe6\xcd\x17/\xfe\xf3?\xfe4\x8d\x17g\xf7\x0f\xb3\x9b\
-\x8b\xd9\xf5\xed\xcd\xe2\x8b\x177\xb7/\xfe\xe9\x1f\x7f\xf3\
-\x87\xff1\x9d\x9e\xfdyq\xb3\xb8\x9b=\xdc\xde\xbd:\
-\xfb\xe3\xc5\xed\xeb\xc5\xd9\xbf^_\xbf\xbb\x7fXf\x9d\
-!\x15(09\xfb\xeb\x7f\xfd\xf9\xec_~|{{\
-\xf7p\xf6\xef\xd7\xef\xdeL\xff\xf5\xe6\xac,3\xffk\
-U\xe6\xab3+\x00g\xff\xfc\xee\xea\xfa\xe2LQ$\
-^\x9e\x9dM\xa7M\x11\xf7\xdf\xbf\xf9\xcd\xd9\xd9YS\
-\xbf\x9b\xfbW7\xf7_\xbc\xf8\xf6\xe1\xe1\xed\xab\xf3\xf3\
-\x9b\xfb2k\x8b+\xf3\xdb\xef\xce\xff:\xfb~\xf1\xa7\
-\xdb\xbb\xff\xb5x}\x8e\x05\xce_\xd4;f\x1f\xbea\
-Y\xd3\xa6\xfc\xff\xbaZ\xfc\xb0\xb8\xfb\x97\x1f\x1f\x167\
-m5\xee\xcfy\xfd\xf6\xab-\xb7w\xe4<GX\xbf\
-\xefb\xfe|\xe3\xdbww\xd7\xe5\xf6\xee\xcd\xf9\xc5\xfc\
-|q\xbd\xf8nq\xf3p\xdf\xd4\x12\xbb\xe4\xf3J>\
-\xbf[\xcc\x1e\xae\xbe_4\xc5|\xd7T\xa8\xbd\xb3)\
-\xfb\xb7\x1d\xe2\xbb\x8b\xcbg\xea\x1f~\xf8\xa1\xfc\xc0K\
-\x22\xcc\xccs\xa0s\xa2iC1\xbd\xff\xe9\xe6a\xf6\
-\xe3t\xfd\xd6\x06\xcc\x0f\xddJ\x00p\xde\x5c\xab\x94\xbb\
-Q\xbd\xfa\xf1\xfa\xea\xe6o\xbd\x95Y^\xed\x96\xde\xe8\
-\xd3\xdb\xe6\xef\xf9\x86\xa7\x8cr\x7f\xfb\xeen\xbe\xb8l\
-\xee\x5c\x94\x9b\xc5\xc3\xf9W\xff\xf1\xd5\xf3\xc5)\x94\x8b\
-\x87\x8b\x0e\x9b\x86\xe9\xfd|\xf6v\xb1V\xeeS\xe6\x0a\
-\xaf\xd9w\x8b\xfb\xb7\xb3\xf9\xe2\xfe\xfc)\xbf\xbd\xbf\xab\
-\xe0\xb8\xcc\xb8\xba\xf8\xe2\xc5\xd7\xb3\x9f\x16w\xdf\xac~\
-\xffpu\xf1\xf0ms\x99b\xf9\xf3\xdb\xc5\xd5\x9bo\
-\x1f\xea\xef\xef\x1bm\xf9\xe7\xdb\x1f\xbfx\x01gp\x86\
-\x14gO\x17n\x1b\xce\x97\xd7\xb7?|\xf1\xe2\xfb\xab\
-\xfb\xab\xd7\xd7\xab\xe2\x167\xb3\xe6\xeb\xf4\xf5l\xfe\xb7\
-7w\xb7\xefn\x9a\xc2n\x16?\x9cun~\x92\xea\
-U[\xdbF\xa0\xb7w\x8b\xfb\xc5\xdd\xf7\xab\xdb\x9f\x00\
-x\xf5\x5cm(L\xcbKORu/\x89\xad\xdfu\
-q;oph\x98\xbe\xb9\x9d6|\xbf\xbf\xba}w\
-?};k\x10n\xda\xf0\xef\x1b\xb4\xafg\xf7\x0d\xed\
-\xf9\x7f\xde7\x1c\xcf/f\xdf_]\x9c\x7f\xb5\xb8\xff\
-\xdb\xc3\xed\xdb\xf3\xfb\xa6\xdf\xbf\xbe\xfdq\xbd\xe4\xdbw\
-\x0fo\xdf=|\xb3h\xbb\xce\xaa\x0a\x0d\xf2\xb5\x19V\
-\x97\x97E=g\xae3X,\xcd\xc1\xf4\xf2\xeaz\xb1\
-\xaa\xe7\xf9\xb7\xb7\xdf-\xce\xdf^\xdd4\xb0\xdf\xdd6\
-_\xe6\xf7\xe7\xb7?\xfe\xf4fqs\xde\xdcq\xddb\
-y>\x9b?,\xbb\xe9\x86Loo\xde|\x90\xfd\x8f\
-\x17o\x1b}3/\xfa\xc1\xcb?\xd5\xcb\xff\xf8\x87\x8b\
-\xc5\xe5\xfd\x93V\xb4\xdf\x11\xda\xdcF\x89\x17\xb3\xbb?\
-\xdf\xcd.\xae\x9a\xae\xbb\xc6d~{}\xbd\x987\x0a\
-2\xbb\xfea\xf6\xd3\xfd\xb3J\xad\xdf\xc2\x8e\xde\xf0\xb9\
-o\xa0l\x08Z\xd8\x1f~\xban\xe4m3\xa6\x0d\x8b\
-\xc6r\xfe\xf6r\xf9\xf9\xfd2\xeb\xb6\xd1\x85\xab\x87\x9f\
-^\xe1\xef_\xac\xe8o//\xef\x17M)\xd0\xfe~\
-,\xa2\xa5d\xc7|qv~\x00kx\x9f5n\xb0\
-&\x5c\xb2>_\x97\xe5\x1f\xff\xf0,\xfc\xdbFQ\xde\
-.\xe6\xad\xadZ\xd3\xa5\x87\x9f\xda\xae\xb9N\xc6\x17\xef\
-\xa9\xed\xdbo\x9a^4U8k\x0c?\xb4\xff\xe2\x06\
-\xc1O\x8d\xc0\xed\x05X^\x87\x8d\xeb\x7f\xff\xe2\x85\xc3\
-&\x83\xf5b\xa7\xb7wWo\xae\x1a\xe5\xe4%\x91T\
-\xd2\xa5\xa8\x1d\x19\x08\xa9\x11\xf8\x97+\x1f\x9a.\xe5\xfb\
-nv\xf7\xb7\xc5\xdd\x1a\xaf\xa6\xc1\xe7\x7fk\xc9\xffx\
-ww\xfb\x03\xfeeq\xb3\x12\xa7\xe1\xbd\xb8i\xb5\xfb\
-\xdd\xc3\xed2\xe3nq\xf9\xbf[S\x03O\xbf\xfe\xbb\
-\xfez\xff\xfe\xaa\x8cO\xc6\xf1\xd5\xa3m\xfc}\xd3\x19\
-\xde\xce\x1e\xbe\xad\x1a\xd7\xfebV\x7fT\xc2&\xe7/\
-g\xad\xdb\xd0\xfc\x9d}}\xa6\xcd\xb7\xa9.\xbfN\x91\
-\x8av\xb2\x97\xb9\xcf\xa4\x7f?{\xb1\xd6\x0b\x1a\xd3r\
-=\xbd{w\xdd\xf4\xf6\xef\x177\xb7\x17\x17M'\xb8\
-\xbb\xfd\xdb\xe2\xd5oa\xf9y\xfc9]Z\xfdWX\
-\xe0\xed\xc3\xefW\xf0L\x1b_\xe7\xee\xe1\xd5M\xe3\xeb\
-<\xf5\x94f\xa0\xbf\xb9oF\xa8\xef\xbex\xd1Z\xa3\
-\xc5\xef\xa0\xc8\xcb\xb3\xbb\xdb\x87\xd9\xc3\xe2w\x18\xf0r\
-Eq\xbd\xfc\x09\x13x\xb9\xea>+~;\xc1\xbe,\
-s\x04\xf0\x95C/\xf4}\xc8\xcb\xa7\x88\xfc\x16\xe0G\
-\x83\xfd\xd7\xd1`\xff\xf5P\xb0\x0d>/\xb0\xa9\x0b\xb6\
-\x1d\x80\xf5\xd7#\xed\xc9\xd7\x87\xda\x13\xfc\xcc\xecI\xf4\
-\xda\x13*z\x08\xf0\xa3\x95\xfc\xebC\x95\x5c\xe2\xf3R\
-\xf2\x18\x80\xfb\xa8~\xc1rP\x97C\x9d\x02\xa4\xa8\xf7\
-o\xf5\x09\x964B\xc5\xda\x8f\xf7:\x06\xe1\xad\xa4\xe3\
-\xfd\x5cC\xe4\x01?\xb76\xd6>~\xae!\xb6\xbe\xcb\
-\xfe\xac\x87\xfd\x5cC\xf4\x0f\xfb\xb9\xed\x97\xd9\xf5\xcep\
-,\xe7\xba\xaf\xbe\xbd[4s\xf3\xdf\xae\xf3b\x02\x7f\
-\x86l\x9d-Q\xe8\xf2\xd2\x9b\xc7\x8c\xff\xbc\xb9zh\
-&\xdf\xef\x9aY\xd8_\xdb)\xe1\xbf\xdd4\x13\xb25\
-\x8a\xff\xa8\xca\xfb\xdd\xec\xe1\xee\xea\xc7\xdfa\x01!R\
-\x99@\x9b\x0a\x92\x01\xca\x84\xb0h\xb6_\xa6A\xc5\xd0\
-\x13_.\xf9\xcc\x1b\x05\x94,\x80\x98\x8e\xab\x9cF\xe9\
-\xa8\x98\x0b\x83\xc72\xe7r\x83\xe6r\x83\xe6\xae\x9dE\
-;\x89ar\x8f\xfel\xaa\x08\x11\xd3\x90\x8a\xbc\x96\x14\
-\x9a\xed\xa9\x22D,\xc3*\xb2\x90\x8b\xf9<\xdfc=\
-\xa0!Dl\x1f\xd6\x90\xfa{\x84\x86TX\xfa\x10\x0b\
-\x1e\xad!P<\x125\x97\x1a\xf2\xfc\x83\xb0\x80\x85\xca\
-\x84\x8b\xa4\x13\xc5bJ/WU\xc5e\xfb\xa32\xac\
-\x0a\xff\xa9\xc9p-\x8c\xc0\x18+\x12\xfa\xe2EP\x91\
-\x10\x13Z\xd1P\x87fg\x8d`b}\xb1\x15\xbb\xda\
-\xa6\xb5Q\x98\xd874b\xdf\xc9\xf5\xd9y\x0f\xeb\xdc\
-P\x89='\xd7\xa7\xd3\x97\x0aZ\xbf\xbe\xe0\x11,\x0a\
-\x22\x09\xe7\x04\x0b\xb0\x0a\xdbd\xda~C3\x9e\xb4\xd7\
-L\xc1'\xa6E\x1d\x94'S\xc9\x82B(\x1d\xe5\x89\
-\x22\x19j\xf4\xac=P\x02QA\xd2\x9e\xd5G\xa28\
-\x93\x13?\xab\x0f\x156u\xb2\xdcC}\xe0D\xb1\x15\
-\x82\x1db+\xa4m\xda7\xb6B\x88?\xeb\x98\xe3y\
-\x04\x0dQL\xafcNH\x0aMPJ@B\xa3\x12\
-\xee\x05Q\xfdS\x18s\x98HO\xa4\x22\xe4\xc3*2\
-[\xb4i\x805n\xb2\xce\xd3\xab\x08i\xbf\x8a\xf8)\
-\x8c\x08\x14\x8e0\x8f\x09\x14!0\x91\x89AA\x08\x9a\
-L\x85\x0b1\xa8\xad+\x0cd\x84<+L\x14Ie\
-$\xaa\x0a\xe3\x85\x1d\x22\xe2Ya\xac\xb8\x03Z\xfa\x93\
-\xc2pIW\x10\xd0\xdd\x15\x86I?<\xea0\x9dl\
-\xd4a:\xe1\xa83,1\xf0!]\x04\x8a\x05\x8b2\
-\xd9`_a\xd0S\x85\xaa\x19N\xef\xc23p\x7f_\
-9\x86\x83\x96\x99\xd9:\xeb^B\xd0\xc4\x16S\x9eh\
-13\xf0\x5cLeB\x05$\x18\x9a|j\x07c\x12\
-\x22\x96\x96\xc8\x8b\x06\xb2z\xed8,\xc5\xdc\x8d\xf3\xb9\
-\xe3x\x11#r[\xe5\x5cn\xd0\x5cn\xd0\xdc-\xfb\
-\x96\xa6b\xb6\xe0\x1e\xd5y\x01\x8d^\xe7\xc5\xf1\x08X\
-\x86\x9a\x02\xb5\x8en\xa6\xae\xec\x8e\xa7\x19\xb5Y\xa1i\
-,\x13D-\x8a\xc4\x93)aI\x16\xcf\xea\xbc \x16\
-&\xe3\x90g\xe7E\xbdppf>\xfb.(E\x92\
-\x95qEC\x95f\x0f\xdf\x054>lg\xc0`w\
-;\x933\xb7\xcd)\xf5\x0e\x93!\x9e]\x0cO\xc5\x0b\
-$%\x01\xdb\x8b\x8d:Z\x9f-\x03\x87\x0d6\x0a\xc2\
-\xe8[m\xda\xfc\x82\xe6\xbb\x9aK\xb0\xd8(\x22Q\x1d\
-9\xf4\xc5\x80\xc8\xbb\x97A\xbb\x9b\xe4\xd7\x19=\xacO\
-j\x97@\xa3\xd7.\xd9x7O\x0b\x99\xb3`ku\
-\xb4\x80\xa2\xa1<Z P\xf7\x94\xd5t\x80\xda\x1e\x15\
-\x5c\xdc\x15'S\xb3\xa2\x1c\x1a\x1d\x8bd\xc5\x5cM\xe2\
-\xd9\x22\xa5\x16\xb7$\xaf\x16\x09\xad\x10:\xab\xd4\xa1\x5c\
-\x0a\x0aR`\xc7\x22\xb9\x98\xc0\x1e\xf1\x06\xcd\x0fw1\
-2\xd8\xa3\x8bU7\x7f\xb8\x8b\x0d\xdf\xb7\xd97^l\
-T\xae\xafo\x91\xc1\xa6\xe2\xbb\x8e\xabz\x97\xfb\x1e*\
-\x0f\x00\xf0\xf1U\x9e4\xb7\xa8\xfc1\xdcV\x95P\x9e\
-`\x11KDY\x8e\x10\xa0h1!*\x16\x9a1A\
-r*)\xed\xb4\x98\x12\x8b\x00U]G-N\x0e\xee\
-\xcf\xba\xaeQ \xd2\xc2\xab\xae\xaf\xd1\x5cn\xd0\xdc-\
-'>(\x9c\xa6{\xc4\xd6\xd4O\x14[\xd3<Ul\
-\xcd\xf0\xe4\xfaB\xea\xfd\xfar\x8c\xe8+1\x1a\xda\x04\
-\x0b%\x0aa\xa3\x14X\x1c\x96YX\xd0\xa35\x8e\x82\
-X\xc2\xa5\xb9\xc6\xa4E\xb5\xa30B\xc5\xd0\x95\xeb\xc4\
-\x18\x09\x8a\x09>\xcdj6h.\xbb4u\x9e#`\
-\x11\xfbD\xde\x12\x07\xf4\xe5\xf5u\xb3ti\xa3I\x07\
-&\xc5\xcb\xa9\xf9\xde|apF\x9c\xba\xeb\x04\xa7u\
-\xc7\xe0\xd9U\xa3\xe8\xfaq\xfa\xec\xe6Q\xec\xd8\xf6\x9b\
-\xd0a\x985\xe3\xcao\xfe\xe1\x1f\xfe\xe1Q\xceZQ\
-\x0ck\xdd\x9f\xde\x09\xce|\xfe\xc18C\x05\xb4\x91\xb2\
-\x9f3\xf5p\xfe\xe1\xdb\xab\x87\xc5\xe6\xc4\xa9\x0b\xe8#\
-\xdfO\x03@M\xf3>\x005-\x07\xc4<\x08>M\
-\xc7\x13\xc3W\xfb\xda\x7f\xff\xe5\xeb\x7f\xfd\xea\x1b\xfaf\
-7\x88*\x9e\x15\xe7.\xfe\xb5Q\xaal\xdd\xda\xf5*\
-\xdc\x9f\xfe\xf4/\x7f\x04x\xb1\x86\x03m@T\x85\xec\
-e\xf3\xe5\x97\xef\xb3\x91\x8a\xc8\x11\x03\xdd+\xdc\xf2\x9b\
-\xbe\x19\x22'\xee\x01iJa\xe1\x8a+\x02\x15\x16\xf1\
-\xfa\x08\xc3\x8a\xb2\xda3\xc0)E\xf9qf3^\x0c\
-\x84-r\xf0>rhG\x04^\xab}\x98\xae\xd5>\
-L\x8fU{\xdcR{=B\xed\xbdPr\xad\xbc\xb6\
-?\x8fUw\xdaRw\xdf\xa7\xee\xd6\xa9\xbb\xd4\xbaG\
-\x01\x00\xaa\x95\xb7\xd5\xef\xb3\xf3\xea\xbb\x1c^{\xff\xa6\
-\xcfc\x91]<\x96\xea\x8b\x02U\xa7\x02\xa90\xc8\xb3\
-\x83\x89\x9cE5\xf4HU\x8e-U\xf6#W9W\
-\x96\xe7\x0f\x8d\x1f\xd6,\xd0\xbe\xf9\xb7\xd7\xff\xa7\xa9\xe0\
-\x92f\xf1\x7f\xdf]\xdd-.\xeaz\xfe\xfd\x97\xef?\
-\x19\xd3\xa6|X[\x13\xbe\xbe\x22\xfcY\xda\xb5J\xac\
-\xc6\xb4?\x5c\xbdz\xfb\xe6\xf2\x7f..7\xb0ZV\
-\xe1\x9b\xabZ\xf27\x0d\xe1\xea\x9e\xf3\xa7\x9bZ\xc9\xce\
-\xd7\xb869\xbf9\xa5QEb\x87\xcf\xdb\xaaVA\
-\xe8s4\xab\xb5\xfa\xf2\xf9\xd9\xd5Zy;\xada\x1d\
-_\xfd\xad\xb5\x8f#\xfbjG\x8e\x9b\x13C\xf6\xd5^\
-0\xf6\xe9\xc0S\x97\x12\x04\x0e\xdei\x03(A\xecu\
-u\xc7\x14\xa3 a\xd6\x8eP\x89>\xaeh\xf9y\x8a\
-Vg:\xfd\xb3 \xe7}\x94\xce\x8bc\xba\xd4\x9e\xe3\
-%\x02k\xf7\xd9 ir\x18\x8a\x08bh_\x1c\xa3\
-\xb3\xee\xb1\x88\x83\xa0-\xa6\xed\xf2\xc7\x8f\xd8\xc6\x9a\xee\
-\x1f\xb5\x8d\xab\xcfs\xfc6^\xe7\x8b\x9aa\xcf\xde\x0d\
-YI\x95\xae\x8f\xc3X@\x14TW\x91\x9d\x0d\x9a\xcb\
-\x0d\x9a\xc6\x11\x8a\x92\x16\xa8<\xbc\xecK%=&S\
-*\xa9\xc9\xb1\x8c\xe3\xc3\x04J\x82\xba\xd3\xc4\x8b)\x90\
-\xeb\x04\xa1\x84\x07\xf8\xcb\xe1V8\xb9%\x0eS?\x81\
-%n}\xac\xf5\x92z\xcb\x97\xfc\x04g\xeda\x8a#\
-'\xee\x95\x13\xf7\xcc\xdd\xdb\xbc\xc6\xfd<\xa2\xf9\x0b\xb3\
-\xe8oi\x97}\xba=gQF\xaa^O\xed\xee\xf5\
-b} \x8b\x05\xc3\xf5\xf4\xfa\xea\x22'\xd0\xd7\x8f\xd6\
-\x08.v\xeaF8\xf9$\xd34\xe4\x18\x8b0<\x9c\
-\xf8iQ[\x066\x89&Y\xd8\xd0\x81p\x82\x05\x8d\
-\x9b$/\xf7\x9b\xaf\x9e:,`\x1a~\xb8\xf8\xd5\x01\
-\x88f\xd8\x1f\x19<\x18\xaf\xa8=2\xa6\x12\xd4\x07\xca\
-P\x00\x019\xeb8*\xc5\x15P\xea\x03\xe5u\x9a\xcb\
-\x0d\x9aF\x0c\x82\xe2\x81\xa4\x03\x8a\x81K\x85\xc0B\x89\
-\x86\xd0\xaa\xc7\x14\xb5\xa8'\xc7\x0e\x03\xe6\xc9cB\xf4\
-y6\xfep\xe4\x88\x22?\xedN}\xdaP7\xfdB\
-B\xdd\xf4Y\x87\xba\xe93\x0eu\xd3\x09C\xdd\xa7\xef\
-\xfdN'\xeb\xfdS\x8cb\x1c\x946\x99Z\x09\xb66\
-}b\x83:\x91\xeb1\xec\xfa\x14\xb3d\xfb\x89\xc94\
-\x0e\xb0\xf0\xcd\xce\xcb\x87\xc5\xddN\xfb\x01W\xa4L\x82\
-/\x9a\xfb\x16\x7f\x9e\xbd\xbb\xbf\xbf\x9a\xdd\xfc\xf3\xf5\xbb\
-\xf6\xfe!\x0e\xed\x04\xe6\xe2\xab\xe6P\x8f\xd9\xc3\xd3)\
-D\x9c\xa2(\x9d\xa5\x00\xebL\x99\x84W\x8b\x02V%\
-\x9f\xb4=\x04\xc4\x8e\xd1\x1eT\x04\xda\x0f.\xa6\xb6\xef\
-\x90{\xe4\x89\x81!r\xfff\xce\xacs\x16.\x12n\
-T7\x83\x89\x17\xc8\x08\xaf\xc3\x0b\x16SO\xcb:\xc0\
-P\x16$V\xb2\x83\x82\x0a\x838\x1a\x97\x94\xb4hA\
-|.s\x8aE@\xdc$\xaa\xfd*\xc4a\x18\xf9\x5c\
-\xf9)r\x09\x93Lz\x92\xb0\x12\x1d\xbc\xa4\x81)c\
-x\xcbE\xc4\xf6\xcdn\x9b8\xd4\xe0\x95\x97T\xc9:\
-\xa88\x171\xb2\xe8\x0c9^\xda\xdf\x18U.(,\
-\xe68\xbcf\x9a\x99\xf9\xd9NF\xfbI\x9c`\x16\x17\
-\x0f\xe3\x09c\x81\x0ce\x7fy0BD\xe0\x83\x081\
-\xf1\xe1\x08e\x09I\xb0:\xa7\x86\xce,\xb5\xa0)@\
-G\xa9a\x08\x94\x09\x17~\x84\x85\x8aj\xf2r\xa7\x0a\
-\x14\xe3\x0c\xf2\xc9\x14-\x0b1:N,\x8b)X\xe6\
-(td\x18\x1d\x94C\xd1!-\x1e\x86V\xf5\x87\xb3\
-\x90\x05V\xfd\xa94\x9d\xb5\xf0\x5cP\x9dx\x87\xe81\
-\x96\x5c~&p8\x0a\xac\xca\xc3\x91\xe4\xccOEG\
-\xaa\x86@\xd5\x8c\xaa-K\xc5\xe0@\xb4Gm\xc1D\
-\x1e\x85\x0e\x8e\xd0\x91O\xcb\xc6$\x1a\x89\xc6D\xa0X\
-\xfb\xd1\x09S\x01\x0b\x03\x1a\x83\x90\xe4)m\x0cS\x85\
-F\x0a30Q\x1dW\xb4\x04\x03!Y\xed?@\x85\
-\x11I\x86W\x1d;\x0a\x85-\xc1\xa1\xe5\x06JQe\
-\xf5\xc9\x94d\x14\x1e\xbe\x83\xc6\xc0\xc1V\xc5W\x9d\xbe\
-\xc2\x82$\x05\x12\xb5\xc2\x92\xb9\xa4\x09\xad\xdb\x83\xa98\
-\x85\xb1\x1c4,M\xa6\xba\xeau\xab^\xb5\xca\xb5Q\
-\x18\xe9\xa0\xcd\x11\xc6C1R\xc9\x02\x86,\x1d\xcb\x9b\
-\xc5]\xac3\xe1B\x93b\x96Us*\xcdv\x8c\xb2\
-8\x9aj\xe4bJ\x8f0!\x03br;\xb5a0\
-\xb4\xf4F\x9f\xb0(\xb0\xf28\x9c\x06m\xb3\x0b\xd1\xbe\
-8\x1d{d9\xd2\x88\xd7\x8b\x02\xca\x98\x11\xea\x97o\
-\x83IYF\xd8\xe0_\xf8\x18N\xca\xe3\xc7\xf0}\xf6\
-2s\xdf^f\xdd}\x03\xd4\xdc\xe7\x17\x17\xbe\xeb\xc6\
-9\xd1\x18\xb7\x97\x19\xc7\x9f\xa0\xd1\x07\x07\xcai\xce\x02\
-`\xb4\x93\xedo\xc68\x1d\x1cp*8\xe8tp\xc8\
-\xe1;\xdd]\x88>\xd8\x1f\x5cHv\xef\x0f\xaf\xa5I\
-\xb6\xff\x86\xc0\x9c\xe7|\x86{o\x08T\x96\x18f>\
-\xbfh:)\xeey\xd2\x84\x0b\xd9\xe1p\x920~\x10\
-N\x12\xe6\xe3\x1c\x950^7\x8b\x90\xa6\x83\xe7\x8b\x8d\
-:\xea\x0ee`\x9b\x86\x9b,\x92<p\xb3\x08\xef\xdb\
-k)\x9c\x1b\x5c\x02\x08\xd3c\x8b\xb9\x5c\xcc\xda\xb4\xeb\
-~N\x11\xdc\xdd\x12_\x5c6i\x03\xcd\x11\xca\xc1\x99\
-C\xd6\x05\xd2b\xb1\xafu!\x01\xdc\xe5\xe0\x95y\xb3\
-\xdbj\xcf\xee@\x02<\xde\xd8\x0e\xfb\xc8}\x06y\xc4\
-\xb3\xdc\x913\x82\x1fq\x87y\x09ui6\xe67\xc7\
-^1(\x8c\xfd8\xe50N\xc7\x9c]n\xce]7\
-\xe7\xb7}s\xe0\xee<\xf9\xc8\x181#\xf4b\x944\
-\x8c\xd1\xd8\xb8\xc4f\x9cc3\x18\xb2\x191\xa9\xe1\x94\
-=\xb6\xabF\x1crP\x5c\xee\xb1\xcf\xdf0./h\
-\xe7\x83\xe2r\x8f\xcd\xf23\x99\xc3B\xd6Y\xefs\xc2\
-\xfa\xe6\xb9\x9d,\xa4{\x9c\x09>t\xbe\xf8\xf0Y\xa4\
-\xc3'\x9c\x0f\x1f\x87z\xf4E\xc5\x99}\xea\xef \xa3\
-\xd5\x7f\xfa\xb8\xf4g\x82$\x935u\x87\x02\x14\x9a5\
-\x90\x00\x051\xa0\x1b\xe4\x89\x02\xc6\x0a\xfe\xa4\xed\x95\xe6\
-\xc0\xe7\xaa\xeet\x8c\xe7\xaaP\x14\xc0\x98d\xcb\x83U\
-w\xe9>X\xed\x9b\x8a\x9b\x15\x22\x11\xad\x8f\x01\x95\x0a\
-a\x88\xd5\x85(\xc6\x059\x14\xb5\xa2\x97V\xc4Bl\
-\x87\x87\x0a\x1c\xc5\xc3%&SX\xb1\xf1\x1c\x11\xc1\x22\
-\xb1\xe1gt\x06\x87G&\xac\x08\xb9V\x93\x87h\xc5\
-1\xc4\xab]\x84\xc2\x86\x12\xa4V\xa37\xbe\xc2#~\
-\x06@\xe4\x94\x80\x84.\xf1\xd0|\x06Dr\xa9\x1fN\
-\xd5\xc5\xb0G9\xea\x10\xeb%\xad\xa5\xd9\x0d\x0e\x9d\xc0\
-(\x04h\x18\x01\xa0C\x110-\x22\x81HU%\x9c\
-K\x068V\x04\x88\x8bk\x98\xd4\x1e\xe2Y\xd0\x89d\
-\x8c\x5c0,W\xea\xcf$\xd7p\xcb\xa6\x8fkV\x8e\
-\xd1\xe2\xf7\xac\xf0\xb9k\xac\x9c\xd5s\xd3\xac\x1e\xeb\xf2\
-\xa8\xb1\xf3\x9a=\xaf\xd9;,0E\x0eN\xca\xe5\x02\
-S(\x8a\x1e\xea\xfb`\xb0^W&\xb6\xbeU.\xf2\
-\xcdx\xc9\x91\xb0\x88\x10r\x05 \xa2D\xa0\xf3'\x06\
-\xc3\xa0\x8d33;\xf8\xf1\x8e\x17\xf2$\xae=\x81\xc8\
-\x8au|\x03\xe5\xe2!\xa8\x5cc\xd2\xc4\x85\xc9\x91V\
->\xd3\xdb\xbb\xc5\xec\xe2/\x8b\x87oo\xdb\xda/.\
-\xdb\x92w\xc2\x0aJ\x18\x82\x18\xb7HEAC\x8e\xe6\
-k\x116\x0c\xf3Q\xfd\x87N:RZq\x05\xef\x0c\
-\x0c\x1e%9\x99+l(\x85\x5c#\xaa\xf9p)\xae\
-\xfd\x90\x8d\x90\x96\xf2\x84\xd6\xc2\xa0\x9eif\x85E\x14\
-\xeav/\xa7\x02\x04\x81\xb5\xcf\xac\xd3\xcc\xbb4C\xee\
-*\x14\x0d4\x0a\x9d`qs7oc\x00T,\xc3\
-HV\x01\x81\x12\xe1\x91\xd1d\xb3\x16\xf0@\x9bhI\
-\xc1\x84\x941\xbd\x8c|\x10B\x91\xfc\xb5\x97u\x84\xa3\
- \x1b\xe9|\x8c\xefeZ\x98M\xa5\xd3\xcb\xb8\xb8\x90\
-q\x9c\xa6\xa7\xf1.ve|O\x0b+A\x96V{\
-\xda\x14\xad\x98\x85D=\x86p\x9dh\xbeF4\xdc\xd7\
-H\xc3\x0c\xbc\xf5\xc4\x95\x90\xc4\xa5\xfd\x1a\xe4\xc2\x22\x13\
-(\x82`\x808a\xa0\xa2\x9c\xa2\x13\x85\x02\xaa\x9a:\
-\xaa\xa3\xe1I;ZA\xd5\xd4\xe88v \x85t\xcd\
-\xabK\xb0\xe0\xce|N\x8a\x0e\xc1\xf5~Wb\xd7#\
-\x8dT8h\xbbM\xe0H\xcfS)s\xf0\x89\xd9\x85\
-\xb7i\xdf\x98v&\x1d\xe9\x81\x07n\xb2\x1e\xf1\xc4\x8c\
-\x89}Pb]\xd8\xde\xcf\x08)\xf0dGB\x93\xe0\
-\xe1\x12\x9b\xb9\x0cI\x0c\x80&\xb1\xa7\xc4fn\xc3\x12\
-#\xcero\x89\xcd<\xc6HlV%^ck\xb1\
-\xc7I\xc4\x97s\xbc\xa4\xfd\x1f\xe3i\xf8\xe2\xf5\xfe\xc7\
-\xa42\x06W\xe6\xef\xc3\x01{\x1cd:\xa7\x99n4\
-\xe6\x188e\x97\xe3\xd4/.\xe6{+\x90\xec\xd4e\
-.._\xef\xaf@\xe2c$f\x1c\x92\xd8\x81\x1d`\
-o\x89\x99\x87%~}\xa9\x0b\x80\xbd%f\x1d!\xb1\
-\x88\x9dd\xe9\x84\x89\xc4\x89\xcc\xa2\x89\xc2\x18\x89a\xd8\
-,\x06.x\xb1\xb7\xc4`\xc3\x12s\xf8\xc5\xc6\x03\x94\
-a\x89!N}\xc0\xac\x99Y\xdf\x9ee;\xca#8\
-NSR\x9eX\xc9`\x14\xc5\xf6\xdc\xff\xa9\x17\x0f\x94\
-\xb4\xf6\x07\x16U\xc3\xe0\xd6\xa5\x22*A\x868\x99Z\
-\x16\xcb0\xb4\x97\x1f\xf0\xe4\xdf\xce.\xbaG\xd0:\x00\
-kg\x03\x12p\xd1\x80\x1a\xdaY'\xb9|\x9f\xe4n\
-I\xa1\x9a\x12#v\x94\xf6;o}*\x89P\x1f^\
-\xd7\x90rD\x9d%J\xdd\x1b\xb4K8\xf5\xe8\x95\x17\
-\xeb\xad\xbcR\x9d\xaab\x81\x94\xcc\xc7\xda\xaer\x100\
-S\xaa\x1f\xae\x05#\x91\xb9\xfbT\x19\xc0Cw\x91\xab\
-\x7f.7\xbc\x83\xd0\x8b\x86CZ\xb4Z\xc7\x01&J\
-/?&R&\xc7\xd8y\x07E\x90\x12\x98&P\x0c\
-\x93U\xe2e?.{\xb7\x0dYD\xac\xb5\x8d\x03d\
-~L\x9c\x1c>u\x9c\xb8\xa4!H\x85)\x0a\xb1\xa6\
-\xf8G\x85\x89~\x85\xa9\xe3\xb8\xf5\xfat\xf5\x91\x9cj\
-\xe1V\xd6\xba\x03\xb4>\xfa\xd9\xb8\xbaZ\xea\x91\xc8(\
-\xfe\xf1-\xae\x09\xf7J$uY\xb8Q\x01\x0eG\xea\
-F\xc2\x12\xd9\xf1Q\xac\x0d\x92VP(N\x91\xa1G\
-\xd1\x9f\x09\x1f\xdd\x88\x9aK\xaf\xf0\x01\x9d\x88M\x814\
-w\xad\xd1S(\x1a`\xe2U\x07\xb3$\x0bs]\xe8\
-\x15Q\x8cY\xe2\x93\x1aF)p\x9f\xf3\x8b\xac\xb3B\
-\x89\xac$\x9b\xad\xafP\x12q7\xaa2S\x01\xcaP\
-\xf9x\x1211\x1e\xc7>\x91\x11\x1b\xe5\x04\xeb\xca\x15\
-\xcdB\xa4\x01\xde=C0\x9d\x09k\xcbW\x9a'\x14\
-\xc4\x0aQ\x84\xe6GE\x81\x8f\x84\x023Q\x8bBI\
-TH\xe9\xa0\x81\xa8\xc5\xcd<*\x1aX $\xa1z\
-\x90\x8c\x85;4\xb4\xb2\xe0\x8c\xa4G\x06\x83\x89\xbd\x17\
-\x0c\xe1z\x04\x97AIQR\xac\xa6\x0b\xb4\x04\x83\xd6\
-\x11\xa4!\xaa:<\x8c\xe3\xc7\xb3C\xe4\x01\xfb\xf4W\
-(\x02\x04V-\x95I\x017\x94\xfaP\xa3\xd2TW\
-\x1fJ\x1a\x11\xca\x91O\xa8\xa2L\xe8=\xe8\x1a\xf2\x08\
-\x0b\xce\x0a\x82@\x84N\xa0\x04\x05\x98\xf9rS\x92\x89\
-KZ\xfb5\xc2\x98\xc9'\x98XD\x8cxbTH\
-9\xc1\x86\xdc\x8fv\xaeg\x5c@\xd0]\xeb3z)\
-\xe9)\x10\xf5\x99$\x17U$\xac\xcf\xfa\x15\x8b&e\
-\xd6w1q\x11\x177Z\x02<\xbf\xbez\xfb\xef\x8f\
-\xaf\x81\x7f\xfa\xbe=\x88\xffD\xc5HY\xdf!\xbf\xfe\
-\xbe\xf7W\xef\xee\xae\x7f\xf7\xdbu\x94\x19\x99_\xfe\xbe\
-\xbdZ\xa3\x00\x8f\xef~_\xbd^\x7f\xfd=\xf0V$\
-\x15\x00B\x9e.\xb4\xed\xd9\xb4\xfc\xab\xbb\xdbw7\x17\
-\xdd\xcc\xffs{u\xb3\x9e\xfb\xddU\xb3\xf4\xed\xfa\xaa\
-\xf9\xdf\xab\xe7\xdb/f\xf7\xdf\xce\xee\xeef?=\x96\
-VsW1\x88WRP\x1f\xb3k\x0d\xbb/\xc3\x9f\
-bHq6\xd1\x09yIa\xd7\xb3/\x9b\xdc\x94\x92\
-\xaen\xcf\xb9x6%\xd0\xd2\xfc\x99O\x18K`\xa0\
-[\x93\x89T\xd2\x81l\xc2Y4\xc8\x8dZ\x06DP\
-\xd2]b\x22^42\x93\xdbL)\xa1\xa9\x13\x8dB\
-D\x86\x8fy\x06I>\xb1(\xee)\x90g_w\xb3\
-\xd3J\x10\x81`\xcb\xb6f#@\x09g\x8f6\x13\x0b\
-\xabx\x9b)\x05)\xa8\xcdD/\x0cM\xaa\x99-_\
-T*h\x19]\xdaV^\x89\x82\x18\xc8]\x16(R\
-\xc2\xd8\xb8\x16\xd6\xcd\xac\x15\xfb\xba\x9b]\xc5\xf8r\x95\
-m\xc8\xf2,1\xad\xca\x92T\xc1.4\xa8V\x14\xc8\
-d\x1dF4)dN\xf4\x0c96\x99.E\xd2\x91\
-\x9f\x1aG\xf2\x83\xed\xf8\xf7\xb3\xb5\xf6\x15.\x12\x08(\
-K\xc6\x1e\x85\xd3!\x9f\xb3\xb5\xcd\xa4\x02\x12\xe8\x13\xd1\
-\x92\xe8-[\xf3\x82\x1e\x81\x13\x85\xe2\xe1\xa4\xb6\xaa\x17\
-\x156\xe7\x9c\xa8\x16\xcd\xb0hE\xc8\x92\x94\x0d\xa9a\
-\x09f\x0eZe\xb6w-\x9b\x17\x12\x80\x96p\x11d\
-Q'\xc0N\xf6\x97\x8f\xd9(n\xcf,\xb0\xcd\xf4\x82\
-\xa0\xfaT\x94g\x9bG\x85R \xde\xabVz\x11\x12\
-\xa7G\x01\x22\xb5\xcd\xc4\x02\xae\xf1,)\x7f\x18\x95\xbf\
-w\xc2u\xad\x05`\x5cy>\xddu\xc47\xb7\x17\x8b\
-v-qcJ\xe6\xf7\xf3\xe5\xe7\xfe\xf1\xbfUd\xef\
-\xc9\x92\x9c\xdc\xccW\x034\xde\xccC\x914\x04\xb5\x09\
-\x14\x11\xc8\xa0lm\xbb\xb3\x81\xa6L\xa6O\xc6\xdf&\
-\xd3\xcc\x82\x82\xe2\x93Xzj\xa0\xb1\x8b\x99w/\xca\
-\xcc\x8e\xef\x9by\xac\xeb\xd5\x22\x0a\x08\x05\xe4\xc70\xf3\
-\xac\xd5\xcc\xef\xd8\xbe\x9b\xda\xe1k\x864\xbd0a\xe0\
-\xba\x1d\x05/j\x88\xd4\xb5\xa3\x88^<\x11\xb8kG\
-\x91\xb4\xa8\xaa\xd1{\x06\x80\xb9\xa8Q\xc8\x9a\xb1`/\
-\x22\x12V\x0d\xe9*\x13S\x8c\xd7\x0ci\xcd\xee\x1a\xd2\
-\x9a\xbdn\xdb\x98K\x0a\xbcg\x05)KDp\xae\x1b\
-R\x93\xe2\xaa\xc4\xbanH\x0d\x8a\x03Kj\x97\x85\xb6\
-\xd5\x8dL\xad\x85u3\xbb\x86\xb4f\xaf\x1bRm\xab\
-\x1bn\xda\xb5\xa4\x86\x05\x02\xdc\xb5\x0b\x8ee\x81\x08\x00\
-\x5c\x07\xd2\xad\x84\x92\x06v-ix\x81 I\xaf\x96\
-\xb46\xe4\x9a!\xad\xd9\xebv4\xa1d\x90ht\xed\
-hH1fe\xadv\xd4\xb3\xb8\x09\xba\xad\x1b,\x97\
-\x92J\xae\x1d3\xeaT\x14\x15=\xab\x19]f\x8az\
-\xb2\xac\x9bQ$*\xa8\xce\xde5\xa3\x8f\xd9\x00H]\
-3\x8a\x98\xc5\x12\xc2\xbav\x14QJx\x8a\xbcgG\
-\x11\x0a @\xac\xd9Q\xe0b\x86h\xd5\x90VT\xd6\
-\xec\xe8\xae\xbeS~~\xbe\xd3\xcfe\xe5\xf3\xa3Zy\
-\xc4\xe2d\xc1\xfa\xf3\x9a\xf9Op%;\x11\xd9\xff\xf7\
-K\xb9\x8d\xf2\x98K\xb9\xc7\x9f\xaa\x99O[K\xd3I\
-'\xc8\x5c\x00\x80&\x04%\xdc\xa8\x95t\x85\xae\x16\xec\
-\xbc\xf6w\x0a\x85P\xa2>x\x8cg\x81\x9f\x84\xe9y\
-#vP\xff\xfa\x0d\xa7\xaf\x90\xbf\xdax\xca\xdc\xf7Z\
-\xe7\x90~V\xac\x7f\xfc\x12\xbf|\x9fUaU\xee\xe7\
-g\xfd\xfc\xe0O\xa9\x10\x1b\xfc\x0cS\xfa\xf9\xc5\x16~\
-\x10_\x02l\xf0s\xf5~~\x09\xdb\xf8\xf9\x1f7\xf8\
-=\x9a\xdc\xaa4\xfb\xac\x16\x03\xea\xd9\x88\x09\xb2\xc7y\
-#\x17\x8b\xc5\xd0\x81\x00]\xd6\xb6\xc7.wZ\xc4\xe2\
-bc\xe5\xc4\x88\xf5q\x06\x87\xecK5:\xee\xf9\x08\
-]\xd62\xe2\xf8\x95\xd1p\xa4\xf6H\x9c\xbe\xbb\xc4\xc6\
-\x8b\xdcC\xe2\xcc\x9fQb\x91<@\x01Dq\x10\x8e\
-\xe1Wm\xf7\xb0\xe6qo\xf1\x86\xdf\x8f\xda\x99L\xce\
-\xb2}g\xb2I\xbb1\x99\x8a\xb5\x1f\xef\xdb\x9e\x8c\x14\
-\xcd%\x93Cw'C\xbd\xfb\xa0\xad\xc9u\x1b#\x14\
-$P\xab\x11g.\xa8\x09\xack\xcfp\x1d\xa1z>\
-\x95fp}\x0f(\xb7\x9f\xa7\x01\x950St\x82X\
-\xdc&R2I\xc8\xc6\x9c,\xca1\xbc\x97\xc7\x0f?\
-\x03P\xa2\x10\x12*\xd6G&Z\xd4\xa2\x0b\x8feI\
-b\x88X\xdbe\xc0I\xf6)\xc0\x03\xa3\xe1\xf9\x05+\
-\x8f\xc7 :lx\xb0\xf2H\xa1\xf0.<\x89m\xad\
-\x1d\xac\xbb\xd4\xa0\xbev\xba\xbd\xee\xa1$;l\x96&\
-\x98\xc0(\xd1mPt\x01\xf8e\x8a.#D\x1f\x9c\
-s\xd5m:\x89%@\xa13]U/\xa0\xa1(u\
-\x02\x96\x05T\x03\xf2y\xde\xa0\x5c\x8c\x81\x86gcE\
-1Sr\xe2\x85\x15\x938\x17\xd3\x98L\xa3\x801\x09\
-k\xfb\x0b\x0b\xb9\x13\xa2L\xa6\x04\x85H\x9c\xac\xf9\xca\
-%\xd3\x8c\xf3\xf0I\x1b\xb1\xd3p\xd7\x918\x10D.\
-\xea\x81\xa4uo\xa1\x14e$\xad\x93X\xec\x92\xcc\xdf\
-'\x99wI\x06\x80\xb4\xa2\xe0\x19\x96\x8f\xd3[EH\
-\xf4\xc9\xd4\xb8\xb4\xe0\x19N\xa6L%\x1d\x10u\x14b\
-'5\xc5i\x85\x8dA;+\x97\xa2\x18\x18v\xb6\x11\
-2\x15P\x0c\xab\xbdN\xb8x&\x90\x1dh\x8b\xbd\xa8\
-\x98\x99\xf9q\xec\xb1\xed\xb2\xb1]\x0eV*T\xeb\xe8\
-\x14Z\x81\xb0\xaaR\x8e\xc5]\x89\xean\xd5.\xc5\xbc\
-K1\x1cD0\x85@i\x90\x22\xc3TX\x9e\xad\x9e\
-\x04\x98!\x13.\x9c@\x086A/\x0c\x09\xd6\x5cV\
-/\x96L\xe3:\xa5\x0d\x1bu\x8b<\xd8\xa8\xb7pd\
-pU\xb1\xb4\xc2\xceH\xdc\x89\x92A\x11\xf2\xea\x0cU\
-\x9aA\x15CwR\x89\xc7n\x08\xee\x84\xe1\x13+\xaa\
-J)6\x99JIAs\xc0Q:6l\xfd\x15\xf1\
-\x97\xa3c\xccG\xd61\x1a\xd61;X\xc7(J\x0a\
-%\xd55Jb\x85HS\xde\x8b\xc4rx5c\x8e\
-\xc5\xc8\x04\xe4@\x1d\xc3\x12b\xe4\xca\xc7\xd21\x18\xd6\
-1\xe0_\x07\xc7\x8a\x98\xf0.\x83\xe3\xaf\x96\xbf\x17?\
-\x1ck\xf9\x7f\xf9\xbd\x92c\x97^\xf9\xab\xe5\xef\xd31\
-\xd6SX\xfecz\x05G\xf2T\xc6\xe8\x18\x8d\xf4.\
-~\xf9N>\xed\xe4\xe4\xff:\xfd\xde\xda\x17IFL\
-\xbf\x07\xfa\xe2p\xe8e|\x94g\x8c\xfe\xe0\x88\xf0\xcd\
-\xe7-:\xc6IE\x1f\x1f\x86\x1d\x1f\x14\x1e\x83\x8e\x8e\
-\x8a\xe6\x9e\x1e\x9d\xf1O\x14F\xc13\xe2I\xc9/_\
-y O\x81\xce\xcfi.8$N\x19\xe3w-N\
-\xe1\xdc\xd9V\x07Q\x1cD\xb8\xcadU *\x0e\x80\
-\xa6c\x04\xb2a\x81\x92\x0f\x15\x88\xb2h0j\xe7\xdd\
-\xc6Y \x08\xbd6\x92[1[?!\x0a\xad\xa0\x90\
-\xd1\x18\xb9v\x18\xcd\xc3\x0e\x95+l\xe9\xe8zV\xe5\
-\x83\x22\x18\xa8TMNafJ\xc4G\xb9*\xcd(\
-\xb9h\x84E\xfeT;\x15|\x9c\xa7G\xc1E\x11C\
-\xad\xbbu\x89\x04\x11\xb3\xba\xafV\xc8\x05\xb53\x89\x84\
-\xa2\x16.8|\xf2\x06QF\xda\xd3\xfb\xff\x1d\xc0\x01\
-'S\xa2\x92\x14\x99\xb6\xfc\x8a\x9e\x181bq_p\
-\xfc\xfa\x9chO\xc4\xec\x84\xa10)\x9a\xec\x150\x91\
-\x82\x99a^\xb5\x8c:$\xf3\x0d\x92y\x87d\xf8%\
-\x14f@*\x13(\xda\xa8S\xd1 \x01\xf5\x89\x14q\
-\x0a\xf5\x98 Iaso\xb0\xc3\xc8Bi\xce\xa3\xb0\
-\x93a\xec\x98\x0f\xc4\xceKZt\xb0\xe3(\x22l\xdc\
-\x85\xae*\xda\xfa\xe5y\xbd<\xd4/\x059Z@\xa0\
-\xa0\x01\x9bf\x03\x9f\x00'!O\xb8\xb0\x87\xa1\xb5!\
-1(\x98,\x18\xcb\xd7\x9d \xaa\xe68\xb5\xa3a\xbb\
-F\xf6iE.\xba\x07\xb9\xc8\xa83\xb5\x83a\xe7\xa8\
-\xc4x\xcd\x89,\x8a\xeeI]\xd5\x09\x85\xc8\xba\xd8}\
-\x9df\xde\xa5\x19\xd4!\xcaTamu\xc8\x15(1\
-&X@\xdd\x89\xad\xf9\x16L\xc0m\x97\xc3\xa5M\x83\
-\x9cL)\x8a\x90\x1b\xe0\x18\x15\xa2\x1d\xfcM\x8e_-\
-\xd7\x07\xb1\xb3],\xd7\xaf\x0f@z\xf1\x93]\x1e\x80\
-\xfc\x8a_/~\xf4\x09/\x1d\x18a\xd7\x09v\x09\xc8\
-\xff\xaa\x17}z\x811\xe2\xa1\xcfg\x88\x9f\x1e\x1b?\
-\xfb\x84\x97K\x9c\xde\xadB9\xce3\xd7\xfaF\xa9\xee\
-K\xa3\x1e\x8d\xd6\xb7\x8b\xab7\xdf6\xf4X4\x83L\
-Wp>\xee\xc9\xca\xc4\xe7-t\xcb\xdd\x9f-]\x02\
-'\x03\xae\xea\xb6\xa4\x13\xc54\x05\xdfZ\x95\x8dWT\
-\xf5\xbfd\x8a\xe4\x83/\xa8\xc2\xc2\xe2\xa6\xabh\xd1V\
-\xa1\xeb\x1b\xaaz\xa4\xb7\xc0\xf7\xa4G\xf5\x14\xeaJ\x0f\
-\x1e\xe9(\x86\xeb\xe2\x93\x88\x07u\xc5G\x22N<\x9a\
-\xf8\x16\xdc\xf3~.&L\x94\xf1\xd2+\xf3\x91\xea\xaa\
-\xac=M\x05\x06\xc0\xaa\xe3+\xcbiG\xaa,g\xf4\
-\x00+\xb9_E\xd7\x0d\xd5\x90\xf5\xc4`\xc3U\xb0h\
-\x8aE\x8c\xd2|1]\xd9P\xa3e\x1c\xc4\x0bi\xec\
-\xea\x04\xd7\xa3\x0f\x88R\xbf\xc1o\x9e\xc7\x80\xa9\x81G\
-a\xad\xd3j\xb6,JBO\x1b/I\xb9\x00F\xdd\
-\x18\x5c\xefy\x1e\x17\xc8\xb4p\xf6\xbc\xc17F\xeeN\
-\xea\xd9\x9c\x84p\xf8N\xad\xcaw\xf6\xea\xbb\xab\x8b\x7f\
-o6\x9d?\xfc\xb5\xb9\xb8gE\x879\x14\x1d\xc1c\
-P\xac?-?;\xed\xb1\x1c\x1eyB&Ss\xa9\
-\x0f\x87\xcc\xa5\x86\x0f8\x8a;s\xd4\xd0|\xd6\xa0|\
-\xbdz\xf0\x13\xa1D\xf9\xa0\xf2P\xa2\xf5\x03@\xd6\xa6\
-\xa1S\xa2{\x14\x88\x12\xa3\x9f5c\x9b\x86X\x17D\
-\x92^\xfe\xb4E\x83\xe4\xa2M\x83\xfc\xd9E\x01\x00\xfb\
-\xcb\xa0\xfe2\x14\xda4X\x86\x10Cff\x7f\x19\xb2\
-\xa5\x0co\xd3p\x19l\xb1\xbd\x8c-\xcdl\xd2\xa6\xe1\
-2$\x07\xe4\xd8\xd2\xde\xaem\x1a.\xc3@{\xf9\xf3\
-\x96\xf6\x8eY\x9b\x86\xf9;\xe2V\x19xK{\xcf\xb8\
-M\xc3e\x04\xcaV\x9d\xe2\xfe\xf6\xbe\xbf\xba\xfe~q\
-7\x5cD\x22n/\xc2\x06_\x1f>\x5c\x86\xf0v\xa8\
-b\x0bT\x97M\x1a.C\xd1%<\xa2\xb7\x0c\xd9\xd2\
-\xe4)m\x1a.\x83I\xb7\xca!\xb4Em\xe7m\x1a\
-.C\x153s\x8b\x1c\xb2\xa5\xfbi\x9b\x86\xcb\x08Q\
-\x01\xf3\xfe2\xb6\xb4\xb9R\x9b\x06\xcb0\x08\x03\x00\xea\
-/cK\x9b\x0b\xb7i\xb8\x0cA\xdb\xaa\xbb\x8a\xfde\
-p\xb6i\xb8\x8c\xa4\xd0 \xea/\x83\xb7\x94\xc1\xc3B\
-8\xa7omp\xd5\xd1c_dDfz\x7f\x19\xbe\
-\xa5\x03\xda,fC\x9d\xa3\xe7\xdd;\xe3\x0e!\x19\xf6\
-~\xeeV\xaf\xa4T1\xeb\xac]\xa4\x92ikk\x17\
-\xa3\xb8\x93R\xdf\xb2\xc1p\xfb\xb0O\x13\x1e[\xac_\
-\xb6\xe9P\x9f&b\xdba\x18\xde\xa6\xc1v\x05I\xe9\
-\xe7O\xfd\xfc_g\x9b\x06\xf9#H\xf6\xf3\x97-:\
-\xb3h\xd30\x7fa\xc2$\xee/\xc3\xb6\x94\x91M\x1a\
-\x96\x81P\xad\x9f\x7fl\xd3\xfb6\x0d\xf3\xb7\xb4m\x83\
-B\xe4\x96v6o\xd3\xb0o\x99\xb1\x85?\x1d\x81\x7f\
-n\xf5]#\xb7\xf9\x95\xd2\xa4]|\xbe\xe0\xed8m\
-ik\xc16\x0d\x97\x91\xaa\xdb\xcb\xd86\x8f\xd06\xed\
-\xe0\x04dDj\xbf-\x05\x18m\xaf\xd5!M\x89\xfb\
-\xcb\xa0-e,\xda4\x5cFJ\xf4\xf3\xdf\xd6\xde\x97\
-m\xdaap\xd6\xed\x0e\x00lio\x876\x0d\x97\x91\
-\xbc\xdd\x07\x87\xd8R\xc6\xeb6\xed0>kl\x1d\x9f\
-\x11\xb6\x94q\xd9\xa6\xe12\x06lH\x22\x8d\xd4)<\
-U\xec\xc1#\x0b\x12\x81o\x89@\x98{\x09w\xc0c\
-\xc6!\xc2\xa8g\xcc6\x19=\x99\x07\xd82h\x98\x8d\
-6\xb8\xc8\x12\xfd\xfcc\xcb\xc0Mm\xdaa\xe2\xc8\xfd\
-\xc6\xdca\xcb\xa07\x1b\x9e\xf9\x1a\xe5\xd6\x1e\x11N[\
-\x0a\xc06\x0d{\xacJ\xb1uD\xf2-\x8d\x9c\x17m\
-\xfa\x84=V+@,u\xe9\x9dbA`\xa5\xf7<\
-V\xe6\xe8\xf5XUz\xb4_m\x8b[\xf9\xbaM\x07\
-{\xac\xbaE1)\xda\xb4\xcb\xe8\xc9\xdbF\x850\x18\
-\xd1\xae\xa3O\xb2K9\xe4\x5c\xb7\xb4\xdd\x03\xe7\xec3\
-\xa1\xf9\xee\xa7\x9c\xc5\xee\xb1\xf3\xd7\x97\x97\xba\x11\x93\x1f\
-q\xc8\x19K\x1c\x80\x06+\xec\x8e\xc6\xbc\xa93~\xa0\
-\xca=\x9ci\x9f3\xce\xe4\xe2\xa8`\x18\x1e\x02\x86\xf1\
-\xee`,..\xebK<\x07U\x83M{\xd0\x18f\
-=\xfe\x00<\x0e;\x04\x8e\x88S\x9d\x80\xc8\x09?\xe7\
-y\x80\x00\x07\xc0!@{h\xc7\xffk\xef\xda\x9a\x9c\
-8\xb2\xf4\xf3\xfaWt\xf0F\xacH\xce\xfd\x82YG\
-@\xdbLL\x84\xbd;\xb1~\xd8G\xa2\x01\xc10\x03\
-\xb4\xa3il\xe3_\xbfu\xaa$\x95J\xa8\xbaQ\xd3\
-=`\x8f%\xe3V~Yu\xf2\x9c\x93\xe7\x96\xa9K\
-\xea\xf3\xe7\x07\xfc\x1e \xc8\x8c:fI_\xa7:\xc8\
-\xae\xa2\x0e:\xc0:\xca\xbf\x0fP\x07\xc3a\xa1\xe3z\
-\xd5\xc1q\x15u\x08\x1c\xa2\x0e\xc2\x03\xd4!\x07ER\
-\xc2\xebUG\xf2U\xd4\x91zS\xb1C\xd2\xffE\xb1\
-c^\xe6\x19])\xf0\xe5\xe7\x92\xebs\xdc]\xef_\
-r\xfe.+|\xc4\xa9\xd2\xc2)\xfc\xf4b\xca\xf8!\
-e\xff\x04\xdbP\xbcJ\x9aU\xe4\x83\x5c\xe5\x04\x9e}\
-\xacm(\xce\xa4\xd9y\xd2\xd7\xe8*fy\x05u\x98\
-\xe3M\xb9\x8a9\x7f\xa9\xaeb\x91\x97\x9e\xce\x0d\xcf\x9f\
-\x07\x1c\xe8*\x96X,\x1fN\x19.s\x15K\xfe\x04\
-\xdbp\xbcJ\xcd\xe1H7e\x1b\x8e\xf2\x19K0g\
-\xbe\x8a:Xo\xaa\x04s\xf6\xc3J\xb0k\xfeIf\
-\x06\xcc\xdf\xe5O2_\xfd\xbc\x8f\xf1\x84\x04\x7f<{\
-\xac\x82_\xcbI\xaew0[\xd6\xa3~\xdc\xe4\xf6\xf8\
-\xa5I\xd8:P\x1d\xa91\x88o\xf6}8\x9bj\xe8\
-5\x89\x18\x17\x88\xe8\xb7\xae\xe3\xc0\x87pbY\xffB\
-A``P}\xab\xa7\x19\x07\xd5\x17a\xad\x05[=\
-\x0f\x93\x7fz\xa2\xe8\xd5\x15\x90\x8fgS\x81\xe7\x01\xe7\
-M\xa64\x96q\xbb\xbad\xe8\x80\xadcq\xc3\x9a\xb2\
-\x8e\x87\xe2\xa6tm\xb3k\x12\x03a^\x8e\xc0C\xe4\
-\xd0-\x11x\xc2}\x98N\xb8\xaf\xf65q\x8f\x17p\
-\xcf\xd7\xc0\xbd7J\x1e\x99\xd7j^\x17\xeft\x01\xef\
-z\x08\xef\xb6\xc5\xbb\x8c\xbcG\x03\x00\x1a\x99\xb7\xbe}\
-\xddg\xc8:\xfa\x9c\x18N\xbca\x92\xbd!b\x1an\
-xUn\xcc$\x80\x1b\x8e\x11\xb0\x83Ds\xc5\xf3x\
-\xcdGL\xe5\x90\xad\x9e-\x9f\xbf\xfd\xe6\xfex\xd6\xdb\
-\xc9\xeb\xe5\xb3\x9f_.\x7f\x99\x88\xf8\xcb\xcb7\xcfN\
-\x7f\xb9\xb3\xfe\x88\xbe\x85\xdf\xda\xd7\xbf\xfe`>\x10\xed\
-d\xb2\x93\x17\xcb\xee`\xa9\xee\x9a\xff\xba\xb5\xa7k\x95\
-A\xfbwr\x06\xbe\xdf\xbd\xec\x8e\x9c;}\xb5\xec\xe2\
-\xdc\xd3eQ\x5cw\x9cuC\xec\xc1O\x9f\xfc\xa3\x9b\
-\x82}=ON\xcf\x9e-\xcf6#\xe0\x04\xee\xb3y\
-7C\xd6?\xfa\x8e\xe2g\x0d\x0fE\xcff\xb2\x9e\x9c\
-\xbc]N\x99\xff\xed\xf4\xb4\x0b\xc1\xd4T\x89\x90u\xda\
-9|~\xbb)\x09\xa4L\xbb*\xdc\x1a5\xf5\x88\xa0\
-\xbd\xaa\xac\xd8l\xb0\xb7\xeb}\x91\xf5\x1d\x82\xef\xce\xce\
-\xbay\xbe\xf3\xea\xe4\xfd\xb2\xe3\xfc\xfb\xfa\xf3x\x95\xc0\
-\xff~\xfaK\xa9\xad\xb2\xe1\xbb\xe5\x08\x95\x8a\xdf\x8e\xe0\
-H\xab\xef\xb9\xf3\xe4\xc9\xe9\xaf\xab\xde\xad\x12\xa6\x08\x8d\
-u\xd3_\xba\xd6\xa3\xb3\xd3\xd7\x7f;[\x82\xd8\x8f\xcb\
-\xf3\xf3\x97o^\x94\x03\xd4c\xa8\x17~}_\xb7\xac\
-\xa0\xa1\x90\xa9\x1a\xe3\xa7_'\xd0\xfbm\xe8m7W\
-\x1d\x9d\xd2^33\xdf\xedx\xffA\xc7z\xbe\x00\x00\
-j\xbezp\xf9\xfa\xa7\xbd\xf8\x96\xb1\xd1x\xe9\x16*\
-#\xba\x1a\xb1\x1bp\x8d\xbd9y\xf2j9\xea\xb2\x1e\
-?\xbf|\xfb\xb2\x03\x07lp\xaa\x0f\xdd\xe9\x9b\xaf\xee\
-\xbf^\x9e\x9f<;9?Y\x9b\xd3\xba\xdd\xed\x18|\
-\xf5\x1f\xf7\xdf\xbc\xbd\xf7\xf6\xf9/\xdd\xab\xe1\xe5\xab\x97\
-O\x97o\xab56{\x17_\x17\xbc\xa5\xc4\xe9\xd7f\
-(\xc6/\xc7\x8c\xcd\xfe\xce\xbf~\xdb\x01\x8c\xe6\xc2\xc4\
-R,\xd60w7\xe3LF\xfd\xf1\xf4\xdd\xd9\xd3\xe5\
-\xc3:)\xee\xed\x15\x86,\xd7\xea\x1c\xf1\xf5\xf7\xcb\xe7\
-\xe7\xff\xd3O\xee\xa8\x98\xd50\xa7?\x9dw\xa7\xce\xfd\
-\xd6\x7f\xe5ce4\xa3\xa8\xe7'g/\x96\xe7k\xb8\
-\xe8M\x91\x92e`\xa3\xfb\x06\xc8\xf2QW\x03\x9dt\
-\xac\xfc\xed\xbf\xffB24J\x9b+Z[h\xddP\
-\xd5`7\xa3\x9d\xa3\x94\xffmfp\xf8&IM\xea\
-\xf3\x93W+\x0f\xef\xee8_\x1e\xaf\xcc\xe7Q\xff\xe8\
-\xf17\xa7?lz\xc6\xeb\xcby\xea,\xbd\x93\xa7#\
-\x95\x9e\x8b\xd2\xf2\x94\x8f\x82\x0b\x1c\x05\xbd\x82\xfchi\
-\xceJ\x8a\x7fDE\x14<o%\xd57x\xca\xfd\xb3\
-g\xcf\xef\xfd\xef\xb7\x8f\xbaCO\x9f\xde\xfb\xbf\xd3\xb3\
-\x7f\x0e\xeeX\xe8\xc9\x93\xd3w\x9d2\xba\xc8\xf5\xec\xe9\
-\xbd\xe7\xc3x/_w\x91\xfd\xee\xdb\x9f_\xfc\xe7\xaf\
-\xaf_\xdd\xbf;v\xd45\x15\xac\xea\xf65\x81\xb3\xe5\
-\xdbr\x83\xce\xa9\xff~~\xfe\xd3\xbd\xbbw\x7f\xea\x0e\
-kl\xa7g/\xba\xfb\xba\xff^\xbf\xac\x1b\xee\xfex\
-\xde\x1d\xd4\xf8\xd7\xa2;\xb8\xfd\x8a\x8f\xee\xd5\x86\xb5\xbb\
-k/\xff\xe6\xab\xafv\x16\x11\xd3c\xd5\xfc\xf1AE\
-\xf9\xe5\xe9\xbd\x14?\xacs\xa7\xab\xe5\xd9]I\xf6o\
-7\xa9\xae\xba\xb0*\xe6\xbdD\x1a\xa0\xe2\x1c%\x0c\xe3\
-\xc8)\xa5\x98\xa7\xa4\x1as\x94T\xe3\xf8AL(\x11\
-\xccSJ\x939J\x91\x0f\x1e\x1d\xf3\x94\x12\xcdRB\
-V\x9f\xa3\xf4\x90\x8f\x8f\xbf\xdd\xe1I\xe6)9\xcfR\
-\xfaV\xbe\xa3\xefrJi^\xe3\x04\x99s\x94\xbe;\
-~D\x8ftJ)\xe6)\x09\xeb\x1c\xa5G\x9d\x9a\x1e\
-M\xad\x80a\x9e\x92\x13\xcdR\xea\x1fSJ\x83\xc6w\
-\xdf\xeb\xbf\xcc1\xe20\xc7\xc8\xeb\xf6\x0ceU\xf5\xa9\
-$>\xe8d\xff\x9c#\x9b\xa1\xe8\xbc-\xc6\x838\x9e\
-\xd0\x13\x5c\xd3\x9b\x99{J\xb3\x88\xf9\xf9\xaf\xe7\x94\xa2\
-\xcf\xcf\x1a\x1b\xcf\xcf\x7f=\xa7\x94\xf2\xba\xe6_q\x96\
-\x922\x1e\xc2\x93\xf2,\xa5\x10\x99\xf7\x93\x87\x1f\xe8I\
-u\x86\x12\xce\x12\xc1\xcemyJ\xc4\xe7\x0c{f+\
-t\xdc\x0f\xb9\xf9M\x8f\xbdj:`\xd6\x8c\x0e\xd5P\
-\xb9\x8b\xf2\x94\x88\xac44\xd1\xc7\xa5\x1aBx|c\
-\xfb)\x9f\xae\x98\xbc\x06\xc58^M1\xf8\xf8\x86\xb6\
-j>Y-n\x87\xaa\x85\x93\x1frL\x89\xc4\xd5\xd4\
-B\x8fol\x17\xe80\xc5D\xc4\x83\x98\xa6\xe4\x98\x0f\
-Z\x00N\xb3\x94\x8e\xe3\xbb\xc8)%\x9d\xa7d>\x1b\
-H\x1f<|p\xfc`\x87\x92_P\x04\x89\xcfQ:\
-\xd6c;\x96)\xa5\x0b\xd2\x04\xa2\xce\x16A\x0f\xbb\xe7\
-4\xb8\xe7|\x9a`@\x9a\x0f\xee\xf5\x9cR\x9a\xd7\xb8\
-\xe0\x05\xa9\xcb\xbb\xa7M)\xcdk\x5c\xcds\x96\xd2\xb7\
-\xf5\x9cR\x9a\xd38\x1e\xe0c\x993\xeeq\xff\xc5\xfa\
-\xb2\x17lR\xbf\x1aP?M0n\xd8T\x8b}\xf3\
-\x8d\xe0\x0e\xf9\xe1\x88\xb9E\x00\x18/\xd0\x1axB\xe0\
-\xd1\xf7\xdb(f\x03\x8b\xf0\x0e\x0dn\x9a\xb6\x86\xd2\xbb\
-c\xf1C\x1a\xd2\x16T\x80\xb1v@\xb4P/@\x1b\
-`\xdf\x96\xa0,2\x88\xde\x92e\x11\xd6\x1c\x1dX:\
-:\xd5\xcf\x90\x85\xb1Pa\x85(-B[0O\x01\
-\x86\x02\x8aR\xdde\x884\xc3\xfc\x88\xee\x1c\xc0\xbfy\
-\xd3\xaeEj$\x08\xf5\xa7\xee\xaf\x7f<`\xf7\x08\xfe\
-ai<\x9c\xd8?\xbcfw\xba\xbd\xde\xea\xda\xf7\x83\
-\xd1\x82f\xe6\xeb\xf3\x1eX\x1d\x85\x17w([j0\
-s\x7f\x9e<\x13*\xcb\x9a\xcc\xb8kt\xfalY\x0b\
-\xcc.v=]=j\xc2\xfb\xc9\xbc\xfc\xd2kbj\
-N_\x0c\x16\x92,\x87\xea\x8b\x04oO\xec\xaeF\x02\
-`\x5c 7\x05a\xb6\x9a\xba\x11%l&l\xd4\xa1\
-edN\x03\xe4\x1a6\xd8\x9d\xc36\x14\xda\x08\x87\xdb\
-\xc4d\x00:\xbc\x07 2\x8a:\x124.\xc3\xf36\
-P)\xc0!\x0b \xc4\xbe\x99\xd4\xdb%\xd0V\x0b\xbd\
-\xb8\x18\xda\x88\xba\x9f\xe3\x11-c\x9b\xf8\x9ci\xca\xc1\
-38z\xacl\xebM\x1b\x97\x08\xf5\x07\xa3\x1b\x7f\xd5\
-F\xc4\x96\x99=\xe2\xc50\x94v\x90\x8e\x8e\xab\xed\xb0\
-ik\x94\xa8C\x0b\x9bG\x16\xa2akD\xb0\x1c+\
-\xa9%\xca\xc2c\xa5\xa8\xe4F\x91\xd5&\xc4j\xe9\xc2\
-{\xb2\x9b\xd7\x83\x8e\x92K\xc1\xba\xcb\xde\xaa\xbd\xeb\x85\
-e5\x83\x91LKg\x22\xd7\xdb\x1f\xa7\xb0\x19\x9di\
-n\xeb,+\x85\xe3\xc2[fh\x19O\x13\x83 Y\
-#\xd1\x80\x90\xdd\x17\xd1\x84\x93\xd9\xb6\x91\x0c\x18D\xf1\
-\x96.@\xb1@\x88\xc6\x8a\x14\x1d\xa9\x09\x18\xc9\xa4E\
-\x1dY\x5c;(Kz\xec\x90Tr\xc5\x0dR\x8a\xb1\
-\x16\x89.\xde\x832\xcc\x13J\xa2\xe2\x80T[\x00\xcd\
-\xa8oSjra\x1a\xec =\x86H\xcc\xa5u\xa8\
-!\x89k~ j\xd2\x0b\xd24\xb2\x9a\x9aH\xb7\x02\
-\xbc\x1a&J\xce\x9b&\x87\x83\xea@\xc3\xccc\x91\x0d\
-P\xb2\xb4\xb4F\xa2\x89sZ\x14@\x94\xcc\x1d\x02\xcc\
-\xc8t\x14\xd9,\x12bD\xbe\x9f*\xfb\x80\x19\xa7\xdb\
-;Q\xa47\x80\x17\x93hv\xd9\x9b\xfa\xeb\xec\x87\xe9\
-<f\xbf\xd1\x10V\x06\xbe\x08[\xd9u\x01f=\xc0\
-le\xbe\xc0\xbaH>\x8aX$w\x17T\x87X\x8f\
-t\xb8T\xa3\x7fe\xd5WS\x8cu\xc7\x91G\xdd_\
-i\xb0\xc8USch\x0e\xfe4\x1dx\xd0\xca4D\
-XA\xfbC.~=\xaam\x9a\xf2\x89\x12\xcbQ>\
-VT\x8f,\xa0\xf7ao\x22\xb2H\xe9E\x95A\xd4\
-H\xef\x11+Q\xfbln\x83\xa8%\x0ch\xddQ\xb2\
-\x11b\xc9V\xe4\xae \xaa\xf3\x15E\xe5CD5\xe5\
-\x02X\xbcD\x0d\xf0Ej/\xaa\x968%\xfc\x80\xd4\
-\xff\xab\xd1\xbf\xb2\xbe\xafD\xad;\xfaY\x15\x1ffU\
-\xf9\x0a\xa2\x06\x5cQT\x9d\x11u\x87\x85\xe3] \xa1\
-\x0dqG\x8f\xb2\xa6\xac.A\xc0\x0e\xcch\xba\xcb\xf0\
-\xae\xe2v\x81\x8cF\xbd\xadG\xactSq\xce:p\
-w\xdcis\x8f&\x10pW\x15\x17\x88\xef\x83\xf8w\
-_\xec\xad`Yp;\xba\xbb-\x08*>\xd7\xdf\xbd\
-\x01\xe7\xcd\xe9\x9b\xe5\x10\x5c\xce\xde\xbdZ\xde[\xfe\xbc\
-\xec\x92H}\xf0\xf3\xec\xf4\x9f\xcbM\x0d34\x87w\
-\xb1\xef\xe1O\xbf\xae\x81\xe2\xae{\xf7\xf3\xde\x93w\xe7\
-\xe7\xdb\xd8?\xba\xdf\x95\xea~_\xaa+nV\xe84\
-t\x15\xf7\x93\x82\xbc\xd6\xfes\xa1\x8c\xfa\xbc\xe0\x0b\xe4\
-\xfa\xab\xd0\x99\xfag\xa8\xf7\xae\xbb>\xfe\xf7]g\x8c\
-\xc6j\xaa\xa3+\xefv\xf9\xbfME|\x03\xcb\x89\xcf\
-\xb4\xfc\xba\xbc\x98as\xbd\xfd\xc7\xaa\xd9\xa7f\x9b7\
-\xa12\xdf\xad\xff\xfe\xac\xe0\xbf\xa8\x0a~\x9c\x7f\xc3\xcb\
-\xe7\xbf\x1e\x9b\x02~\xcc\x81\xc6\xb7>\xbe\xa0\x1f\xed\xe7\
-\xc0\x02\x8a\xcd\xb3w\xc0]\xc6\xf5\xd6\x97\xb9\x1c(M\
-]]\xd8\xc0\xbd\xc2\xfa\xad\xcf\xb1 \xb8qay\xaf\
-\xb0y\xebK\x5c\x12\xcc\x0b{\x81\x80\xbaO@\xc7[\
-\xbf\xcb\x85\xc0\xa4\x8e\xff\xfc\x95\xf9e\x0b\x87\xa9\xcey\
-\x87\xfb\xb1\x93\x0c\xa8\xae\x1f\x08\x916&3\xb3E\xc5\
-\xcfI\xb3\xc8~\x09\xab\x91\xaf\xb6\xde\x1c\xe8?%\xba\
-\xf3\xe5\x90W'O\x96\xafV\x9f\x1c=\xaa\xbe}u\
-\xd5\x9d2*\xa8g\xd5\x0f\xdcx\xd1\x07\xec\xa8\xe5\xea\
-\x10\xe9\xf7\xdf\x86\xfdMU\x8aV\xb2\xad\xf2\x0b\x9b\xa3\
-\x98\x84,\xef\xd0d\xe7\x86X\xf4\xb2\xc0\x9f\xa0dL\
-\xf8\xf5T\x9d\xa3\xc0\x17h\xd78v\xb5[\x14M3\
-\xd3>J\xc7g\xf5\xd1\xc85\xda+\xfc\xd5\xcb\xee\xcf\
-=Yc\xcfN\xba\xcf:\x9f\x9d\x9d\xbc\x1fX\x1b\xd0\
-\x8b\xabYe\xbe=\xf5\xef\xf0\x16U\x80\xd0\x10\x9a\x00\
-R\xd2\xbbf\x03\xb2d\xad\xd8\x8cn\x08X\x183\xa7\
-\x0f\xf5}5\xc3\xb5\xac\xb0Z\x06\xd5\xeah\x904U\
-@\x91\x85a3\x16\xa4\xec\xb0\x85Q\xf3\x100\xee\x1b\
-\x15$\xea\xaf6BM\xf6\xed\xbb\xac\xb1i8\xae\xe8\
-zC\xaaQ\x861Q\xab9\xa4\x0c\x07H\xe3\x0e\xb3\
-\x06aX\xb9\xb31\x93\xb0\xf7Xy\x8eV\xd9\xe1\x18\
->\xdc\xaa\xc9=\x8f\x89\x0dA\xc1\xeaBiINZ\
-E-\x00\x98P\x87qS\x0e\xc2\xa3\xacF\xe7h\xf5\
-\xa2\x88#\xe9\xd0\xf0h`C\xa3\xb7P\x1b\x84\xaf\xd1\
-(\x13\xd8\x17\xae-\x91\xc3K\xa7f\xae\xc6\x059\xa7\
-+\x17\xf3\x14H\xfd\x8d\x026\x08TiO\x92\xb9J\
--pr\x89Z\x9ef&k\xd4\x80b\xe8U\x0e\xc8\
-\x22\xa0\xf4Qu\x1d7\x1b\xe6\x80e \xb40\x19\xfa\
-HV\xecVC\xaa\xfc\x1c\x89I\xf6\xf2\x81o\x06\xb5\
-\x85B\xaf\x87m\xe6\x14\xd7\x0a\xdb\x08\xb1P\xea\xf5*\
-6\x8aZ\xd8\xa0\xff\x84\xd6\xdf\xb5Q\x93dK\xf6U\
-\x83\xb3Y\xac\x1bX\xb1}P\xb9\xa0/j\x16\xd0Q\
-\xa9\xa6F5\x8c:\x8c[x\x04a\xd1\xf5\x9e#\xe4\
-a\xf6\x0b\x01\xe0p\xee\x8d\xd2\x11\xa3&?\xd5\x99\xca\
- Z\x9a\x91\xf3h\xdb{\xf6\x89X17\xe0\xf9%\
-'\xb1v-tv\xaeS.\x1a\xe4\xd0q\x07\x1b\x22\
-\x06\x92\xdc>4\xf9\x12\x1b\xdc\xfe\xe8XR\xde=\x0d\
-$\xf1/\x09 \xd3@QN\xe3 Y\xe5zH\xaa\
-\xac\xd6\x0e\xa8\xa8\xde\x17\xfa\xc8i\x89e\x19u\xa1\x16\
-\xc6\x22\x8e\xa9\xbdk\xba(vP\x92+A\xbf'\xe0\
-\xe5\x10\x84}\xf40\x16\xc0\xb2S\xb4f\x04\x99T\x01\
-D\x14\xdd\xec\x08u\x08\xe7\x5cq\xc4\x12$'\x98\x94\
-\x1d1y\xdd=\xa2\xda\x18\x01\xd5\xb7)ZS\x89\x08\
-\xdf\x1e\xdb\x1b\x9b\x19\x97en\xd8D\xcc\x06\xce\xc8\x83\
-S{\x04K.\x90\xa0!\x84D)\xc3!\x01{\x88\
-\xd2@\xfa\xd5\xad (\xf77\xab\x07\x944)\xc5\x0f\
-B\xa1\xd1\xc2\xa0\x0a`k@.\xa4\x1dV\x83s\xac\
-03\xf3>P9X\xd4jmDK\xd1\x09\x046\
-AC\x9b \x80\xc4\x04\xf5l(\xe1\xa8\x13T\xa2\x85\
-brN\xd1\x8au\x8cN\x13\x94\xbd\x05\x82\x88OP\
-\xa4F\xc9AYr\x15\xeahT\xee\x86\xe4lz\x94\
-\xda\x14\x1c4\x16X\xfe\x19\xa1Z\xf2kbT\x81\xdb\
-0-Hu\xd8107G+\x13\x09\xf14\xaah\
- \x22fe_\x12F\x94\xfbL\xee\xb7\xa3\x1f*B\
-\x19\xf41\x82\xb0\x91\x04A\xc94\xa2BMTSK\
-&\x8b\x96\x92\x01\xb2\x85\x1e\x17J\xe9\x06\xba\x85\x9a7\
-wR\x89\xc2\x92\x8d\x93Gl\xa2\xa7\x11\x1d\xf5\x7f\xbc\
-\x8dZ\x03\xb0\xa0\x18\xc7)L\xc2\xc9|\xe4h\xc4\xb6\
-\xb9\x9fA\x11\xac\xb9\x92\xf4\x097\x1a\x91\xa0\xe0\x96\xe5\
-\x7f\xbfO+\xfb\xc2\x1e\x03]\xbe.\x0a\xfdz\xf6\x0d\
-46\xfa\x92C\xd7|\xedc\x81\x97\xd4>\xae\xa99\
-\xd4>\x12\xe6\xa5R\x06\x02\x95\xc2(8%\xaa\x0e1\
-5\xd2\x82\x5cWz'-\xa5{\xac2_%\xa0\x9e\
-\xb0V\xd7PpD@jT\xa63\x0f\x8f,L,\
-I\xfbL\xe7I\xa8yC\x99\xce\x14o0\xd3\xcd\x17\
-\xcd\xf3\xc9O\xfeL~\x7f&\xbf\x9bI~!\xcd,\
-\xc5\xae7#\x16\xda\x81\x98\x7f\xe6\xc9\x7f\x93<\xa9\x90\
-c\xac\xdb\xed\xb4\xd0\x9d]2\x1c3\x89\xe3\x87\x99\xc4\
-\xe1\xc3Lb\xb9\x93I\x1cv3\x89\xebn&q\xfd\
-0\x93\xb8~\x98I\x5cv3\x89\xcb\x07\x99\xc4\xe9\xc3\
-L\xe28f\x92\xd9\x18\xcf\x17\xd6\x07\xf6\xbb\xaf\x0f.\
-\xcf\x93w\xc6D\x89\xd8\xdc\x16H\xd1\x22\x5c\xf8*\x8b\
-\xc18Lc\xd7\xbdO9\xda1I\x93\x95\xb7\x80s\
-y\x8b7\xab\xcd7\x17a\xce\x0d\x00\xd1H5\xb0\x03\
-\xa6\xb7\xecq%b\xe2\x02/|'\xe7\xf2\xba\xe2\x22\
-\x93s\xf8}\x9a\x9c\x13\xed\x94\xa4\x88\xadwx\xcd\xf5\
-6\xca\xf6\xe6Z\xacv\xc9pks-\xc6\xbd\xb5z\
--\xfde\xd0?p\xdca\x1bo\xdd\xdaa\xcb\xed\x0d\
-6\xe4\x06\x8c\xd4!\x9b]\x1b\xd4\x86j\x05mv\x93\
-\xa6\xfc\xed\x0b\x9c\x0e\xfa)^\x94\xcdBh\xde\x8b.\
-0\x02\xfaR\xbch\xd7i\xe6\xdcj\xf4\xa2\x01\xf0h\
-\xae\x98\xa1k@\xb22\x14\x1a\xedz\xe2\xfe\xa5\x1d\xc1\
-\x9c\xd6\x0e\xde\xc0\xde\x1f\xa8\x5cn\xefh\xad\x01\x8a\xb3\
-\xfa\x15\xb57\xef\x1a\x9c6u\x8da\xdb\xb0\xf6:\xa9\
-\xdf\xe5\x9c\xee\xce\xc2\xf0Wb\xd5a{\x15\x94\xf2\xd1\
-\xa6\x09-\x093E\x17w\xb21\xd8P\x05\xb6L\x12\
-\xb2\xbc=_\x1bD\xea'\xf2}Csg\x9fa\xee\
->]\xd1\x87gS\x8f/9\x0e(c\x09h\xdc\x12\
-\xd9\xb8\xf6\xc1\x19\x1b\x93*\xf5\x8b9w\x12\xa7#\x8e\
-\xa6\x12\xea\xd1\x87pN\x009\x12k\xa0\x89\xe6\x1b\x8c\
-\xab\x9e\xc6\xa6NA\xb8\x85\xba\xb6d \xcc\x1a\x87\x0c\
-3t`F\xb3%\x84\x13_-\xc2D\xfa\xe1\xf3\x11\
-\xf0\xc5\xceGXs\xac\x9cG\xd0\xd8\x83p\x1b\x93h\
-!\xe2\x93\xeb4\x1b\x1bR\xe4P\x8a\x130\xc1\xb0.\
-\xb7\x00\x8f\x9a\x0c0T\xebS\xa6\x81\x22\xf3\x91hs\
-\xa3D\x1f\xb1\x9a\xf4h\xc6(l[(W\x0eL\xd7\
-\x1e\xc3 \xef\x98$m\x14\xe1Z3\xc9\xa9\x80\xf2\x07\
-\xb0\xa3D\xb8\x82\x1d\xd1\xef\xcc\xaf)\x1a\x12e`_\
-?\x99\x1by\xcdQ\x88\x93da\x96AaG\xac\xcd\
-\xd4\xb5\x90$\x02\x8b\x9aKjh)\xe2\x85:\x889\
-\x17=W\xa0,\x885\x89\xcb8\xa4\x0f\xa5\xfd\xb8B\
-\x22\xb1Z\xe1z\x14Je\x8e\xe9\xa0\x13T\xb29$\
-jNP\x83\x06J\x1e}\x01IM\x18\xb2\x0c\x11\x1b\
-9\x93\xe2\x91{\x0b\xc2@*sgB3\xe9\x17\x90\
-\x988\xc8\x8d\xac\x0e\xabO\x88\xa0B\x9a\xd4\x95\x14\x0a\
-)G\xc1\x0dB\x98\xa2\xa7\x08FAW\xb0\xa4\xa3\x1f\
-\xf6+\xcb\x9b\x00)p\x99.\x90\xa8\xea\x11gC'\
-\xd5,\x0c\x01\x1d\xfdH\xa0\xa5:\x04\xf7\x98\x92Z\xef\
-6\xd9\xaa\x97\xa2PH\x87\xa4\x81\x22*Y\x8f1\xb8\
-\xe9\x9e\x91\xf7Zvn>\xcbQ\xff\xea\x87`\xbe\xf9\
-\x7f\xaf\xd7Z\xe4TM\x01\x00\
-\x00\x00\x17\x91\
-\x1f\
-\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xed=io\xe3F\x96\
-\xdf\xfbWp\x9d/i\xacH\xd5}\xb8\x8f\x01f\x82\
-\x04\x016X`&\xc1\xcc\xb7\x80\x96([\x1bY2\
-$\xb9-\xf7\xaf\xdf\xf7\x8aW\x91,Q\x94,\xbb\x03\
-\xc7v:\xa6\xaa^]\xaf\xde\xcd\xaa\xa7\x8f\x7f\xdb\xdd\
-.\xa2/\xd9z3_-?]\xd0\x84\x5cD\xd9r\
-\xb2\x9a\xce\x97\xd7\x9f.~\xfb\xf5\xc7\xd8\x5cD\x9bm\
-\xba\x9c\xa6\x8b\xd52\xfbt\xb1\x5c]\xfc\xed\xf3\xbb\x8f\
-\xff\x15\xc7\xd1?\xd6Y\xba\xcd\xa6\xd1\xc3|{\x13\xfd\
-\xbc\xfcc3I\xef\xb2\xe8\xfb\x9b\xed\xf6\xeer<~\
-xxH\xe6Ea\xb2Z_\x8f\xdfGq\xfc\xf9\xdd\
-\xbb\x8f\x9b/\xd7\xef\xa2(\x82q\x97\x9b\xcb\xe9\xe4\xd3\
-E\xd1\xe0\xee~\xbdp\x80\xd3\xc98[d\xb7\xd9r\
-\xbb\x19\xd3\x84\x8e/j\xf0I\x0d>\xc1\xd1\xe7_\xb2\
-\xc9\xea\xf6v\xb5\xdc\xb8\x96\xcb\xcdw\x1e\xf0z:\xab\
-\xa0q6\x0f\xdc\x01Qk\xed\x98\xb01c1@\xc4\
-\x9b\xc7\xe56\xdd\xc5\xcd\xa60\xc7PSF\x08\x19C\
-]\x0d9\x0c\xear\xb7\x00T\xec\x9d\x8c\xab\xf5G\x07\
-\xf4\xdf\xc1\xbf\xaaAY\x90lV\xf7\xebI6\x83\x96\
-Y\xb2\xcc\xb6\xe3\x1f~\xfd\xa1\xaa\x8cI2\xddN\xbd\
-nJ\xec7\xc6ml\xc92\xbd\xcd6w\xe9$\xdb\
-\x8c\xcbr\xd7\xfea>\xdd\xde\x0050\xe3>\xded\
-\xf3\xeb\x9bm\xfdy>\xfdt\x01\xeb\xe3\x82\xe4\x9f\xcb\
-\x19\x5cVtD\x12\xcer\xd0\xa2[\xbfJ\x98\x84F\
-k\xab\x15q \x0d\xe2kt7]Mp\x86\x9f.\
-\xbe\xaeV\xb7\xf1\xea~\x9b\xc0\xa8_\x9b\xfdB\xe9\xdd\
-\xfd\xf6\xf7l\xb7\xcd\x96y7\xb00o\x95\xae\xda\xb5\
-K\x1aK\xac:\xc8vw\xab\xf56\x9e\xcd\x17Y>\
-\xd8\xf8fu\x9b\x8d\xef\xe6KX\xf6z\x05\x0f\x93\xcd\
-x\xb5{\xbc\xce\x96\xf1|\x02\x946\x86v\x8b\xf4j\
-\x91\x8d\xd3\xc9v\xee\x0an\xd3\xc5b,\xccN\x98q\
-5\xd5\xbb\xe5up\xa0\xdd\xf4\x0e6\x96r\x19\xac}\
-\xacj?C\xf5\xc7i6\xdb X\x8es\xfc\xc4\x05\
-%\xae\x0ej\x81l\xb2t\xfd\xd3:\x9d\xce\x81Yr\
-8\xaf\xcb\xc9j\xb1\xc8&\xb0o\xe9\xe2!}\xdc\x5c\
-T\x00\xd0U\xb3)\xb7T\x15\x9dB\xb7\x9b\xed\xea\xae\
-\x84\x85\xdd\xd8>.\x00+X\x18C\x8f\xab\xf5\xe5w\
-\xf4\x8aI\xce?\xb8\xa2\x15\x90\xcf|\xfbxI?\x5c\
-\xd4mV\xb3\xd9&\x83\x81\x89W\xe6\x88\x06Z\xc0X\
- R\xc6O\x1b\x8d\x84F\xa3\xc1\xd1\x18\xa9F\xfb8\
-n.\xfbiht\x5c{y\xb3\xce@\xca|\xf7\x9f\
-_\xfe\xe7\xe7\x1f~\xb7\xbf\xc7\xaa\x07\xcd\xccP#\xaa\
-\xfa\xeb\xa2\xf4\xb7\xe5|\x0br\xe4~\x93\xad\xff\x85\xbc\
-\xf8\xbf\xcb\xdf6Y\x07\xea\xd7u\xba\xdc\x00\xe3\xdf~\
-\xba\xd8\xe2\xe3\x02D\xef\xf7\xcc&Vq%\xed(\x06\
-\x92I\x94b\xf2}=?\x0a(\x11\x168\xd1\xaa\x1a\
-5\x8fPjd\xc2\xb9\x10\xa4\x9e\xcb\x8e\x01\xac\x14\xd8\
-\x83\xf1`\x99\x0f[aq\x0f\xbe`\xb9\x01,\x0c[\
-%\xce\xd5\x8a\x84\x0bn\x08o\xcc\x95\x12\x06\xc5B7\
-\xa6jT\x22\xb9\x94\xd66\xa6\x0a\x1dHD\x86\xd9G\
-\xca!\xb2\x0c\x10\x9c\x9c\xe0o\x0fy\x97\xc4\xa5X,\
-\xf7\x93r\x09\xa5\x85f\xf1\x81!\xb3\xd9\x8cd\xb3!\
-\x1c\x95p\xca\xadPz\xd8\xc0$\xa6\xfd\x03\xa7iz\
-\x95\xdaA\x03k\x06RB)\xbb\x7f\xe0\x10#\x86\xf0\
-\x0b['\xe9\x10\xfc\x0a\x0f\xbf\x7f\x06\xe6=\x96\xac\x03\
-\xcc{\x9bn\xd7\xf3\xdd\xf74\xb1\xf8c\xe8\x88\xc0\xaf\
-\xca?Y\x09|\xccXB8cz\x14+N\x81!\
--\xb3/\xc0\xd38\xd1t\xf1,hlv\x8dh4\
-gC#\xe0\xca\xfd\x18\x87\xc6\xe2\x13\x05,\x0a\x05\xeb\
-\xe6\x14\x1f\xa9\x86\xd5r]#q\xb2C$\x22\x00\xf3\
-$\xc8\xe4\x11\x0d\x1c\x82]\xd0\xbat\x16\x84\x9d\x05a\
-\xd7\x9f.\x10\xb1`\xf9\x1c\x12\x95G\xa1\xb5\xd9\x87\x16\
-\x96\xf5S\xa9%OG\xef\x1e\x15c\x90\xf0(o\xd3\
-\xa3N(Umj\xd4Fs\xd3\xa6F\x93hi\x0c\
-oP#\x85!\x18\xb7\x034\xcc\xf1\x86\x8d\xc3\xd6p\
-Sc\xe6~N4l`,q\x94a\x13\x1am\xb0\
-a\x03\xa3\xa9C\xb2\xf1\x1cL\xdd\xc2'\xa5\xa6\x9f\xb9\
-=\xea\x1cF}\xc8\x8dF'\xb2\xc1\x88`\xcc\x18-\
-\x89'\xcd\x90\x11\x8dM\x8c\xa0\x86\xcb\x06#\x828\x94\
-Z[\xdb`D\x0a\xa0\x9a1\xd2\x9dMW\x88\x10\x90\
-\xbeT\x12.\xc5\x08|(\xca\x09\x98\x1b\x84\x8f\x8aG\
-\x94-\x08 \xa4\x02i\xc2\x13\xcb\x15e\x9c\x8f(\x05\
-\x8dH@\xb6\xbe\x1fb\x19\x05\xd08\x9cP\xa6|6\
-\x19D(A\xb2\xa4\x9e\x05\xbc\xdfV(}\xbbV\x87\
-\x89\x94 E\x89\xc7\xc8\xc1\x19^\xa539k\x99L\
-$a\x80G`w\xf6a\xd0\xf8*8\xbe\x96R1\
-\xea\xedcp|\xc3\xafdv\xd5\x1e_X\xb0&-\
-\xeb\x1b?h\x9e\xe8\xd9D\xb5\xfb\xd2F\x08\xc3\xb4\x19\
-\xcc\x9f\xa0\xc8\xbf\x01\x7f\xc2\x0c{\xf8S3o#\x9d\
-\x1a\xd4 \xbbA\xb3\xd1\x06\xf7\x09\x96(\xa9%k0\
-_\x17t\x16\x02\x05\xde\xe3,\x91\x94i\xd5uuB\
-v\x90\x06\xfa\xe29\xbbY\x0e\x8c!\xb4\xe3B\x0b\x9e\
-\x00\xb0\xdc\xc8\x01X\xc58\x9aF\x14\x14\x856\xf0\xa8\
-$\x10&h\xf6\xf7\x03\x85\xcd3h\x16\xc4\xf4p\xa2\
-\xca\xcd\x94S5\x0b3=,<p\xb4\xe1\x9a\x85\x99\
-\x83\x94;\x9b/\xb6\xd9\xba\xa2\x19\x1c5\x9e/\xa1\xe8\
-n\x05V\xc3|\xb5\x8cs\x08\xd8\x89\xcd?\x7f\xfa\xfb\
-\xc5Q\x88\xce\x9b\xc24\xbc\x98\xc4,\xfb)\xbd\xdfl\
-\xe6\xe9\xf2\xef\x8b\xfb\xb57\xe9C\x1d\x22~\xa6?d\
-_\xe6nZ(Q\x94\xd2(\x7fuk\xe9\xcd\x11`\
-t\xe3!!\x9f\xd2\xb3\xb1-\xf8\xbd*\xe6\x9e\x93\x18\
-`]\x11\xd0e'{\x1f\xce\x5c\xa6h\xbf\x0aC\x14\
-<\x03\xcb\x81\x024\xc0\x5c\xa2e([0\x00\xad\xa6\
-MC\xd9\xaa\xc4(#\xa9l\x8a\x88\x0e\xec,\x08\xdb\
-\x90\x11\xe7g\xcd\x0a\x9b/d\xf8a\xd4\x22\x96q\x8f\
-c|n\xe3\x0f\x9d7\x18\xf1`d\xeb%\xd8T\xd0\
-\xe7`Sp\xe5\x8c\xe5\x82\x9a~.\x15t/\x97\x9e\
-/0@\xc9\xef\xb1\xe9\xa17\xb4z\x8f\x0d\xeb9\xc7\
-\x09\xb4\x98\x12\xc6c\x0ct\x9d8O81\xcc3r\
-\x9d\xebdMB\x0d#\x1e,s\x06\xb1\x92F\x0d\x0f\
-\xcd5\x97rDl\xae9G\xea\x05\xe9\xcax\x9cQ\
-\xd2\x93Pe<./}Z<\xeeG\xf7\x13\x8a\x0f\
-\xd9X==\x1a%\xc1~\xe1\x81\xde5=\x1c}\xfa\
-6\xaa\x80\x1d\xedd\x9dG\x15<\xaf\xb1\xf8\x9cA\x13\
-\x22\xa8\x17\x09\x0d\xb3\xf0\xb1\xc1\xbd\xcd\xdd:K\xa7\xbf\
-d\xdb\x9b\x15nQ6\xc3Y5\x19\xdc\xf0D\x11\x22\
-\x9b\xb1\x11@\x0d\xe1\xe0D6\x19\x1cX;\xe1hy\
-\xf9\x1c\x04\xd60\x9a+'8\x98\xf9\x82_*\xf2A\
-\x04\x8f{b\x1f\x1e\x9c\x8de\xa8\xd3\x84\xe6\x01P\xd5\
-\xcf\xab{\x94\xe6\xcb\x05]\xc0%\x01\xb4\xfe\x09\xb4.\
-\xd3\xe2Y\x8ccj\x19\x15D\xb1\xd6\xe2\xdb\xc6\xb1V\
-\x7f.\xe3\x98\xdb\xf3\xc5\x94\xff\x94\xc6\xf1\x8bXr\xec\
-\x99hJ\x0a\x05\xfe\x94\xed\xa7)\xc1\xf6\xd2\xd4\xf9\x15\
-B\x90\xa6\x9a J\x883\xbc\xab\xad\xc2\x1c\x84\x81&\
-\xe0\x18K\x04\x85\x00\xea\xd1(GVDr\xc2\xb4A\
-r\x93DK%G\xb1P\x09W`\xd8b\xc4\x9da\
-\xc0\x1dTf+\xe2Nh\x229\x15\x0d\xb5BM\xa2\
-@\x89h\xdaP+]P(\x94\x00J\xa1[v\xde\
-\xf7?-\x15\xc4)\xebeY\xcf\xb6G^\xd2\xf8J\
-\x0c\xd4p\x93\x97\x04\xe2\x881B\x1b\xbc\xd4\x85\x9d\x05\
-a\xeb72\xc36\xf2\x19\xc2D\x88\x85\x97R\xc3\xb8\
-\xcf/\xa7\x0b9\xfd\x16/ \x0eQ\x15;\xe5\xfd\xc3\
-\xf3\xd2\xde\xd1\xd6\x1b7V\xc7:\xe6\xfb\x08\xa7\x0a\x03\
-\x18kc\xd1x\xc5?\xd0\xa5\x9aM\xf0\xb7Eg\xc7\
-\xd1\x8e\xc1\xdfv\x0f!\xd3N2\x06\x0e\x96n{\xf2\
-\xf9\xe9\x1c\x02NV\xac\x0f\x9b\x8e\x00\xc9c\xb6\xc7x\
-\xd4\x8cs\xad\xa5=\xb0f\x92\xcd\x02g,\x86\x0c-\
-]x'4\xb4\xb1\x84\x09\xdf\xcf\x09\x1f\xef\xe0\x19\xcd\
-\xba'\x1e\x86\x0c\xada\x83CoF\x0e\x8c8\xc9&\
-W\x93\xab}\x1b|\xdcY\x8a\xae\xb7\xc4\x81\xfa\x0fL\
-\x9d\x09r\x02]\x12\xab\xcc){\x04\xa3\xf1\xe3\x91\x94\
-f\x93Y\x87\x0b>\x9c\x0bKBR\x036\x86>\x84\
-)!\x19\x89i\x98\xb4\x0f\x90U\x96\xc1>?\x89\x8b\
-\x05\xfe\x0e\xe1b\x91\xbfS\x08i\x02i\x15\x8a!~\
-x\x9b`\xa9,\xb6q\xe8M\xe3\x81\xad\x9a\xa9\x99\x9c\
-\xc9\xf3\xd0\xf3S\xecFK\xfb\xce\x08\xe1\xcb\xc6\x86\xa5\
-\xa68*\x0b?t\xefB|x\x22E*\xaf\x14M\
-\xb5\x00,\xcbc&j\xf0\x89\x99g\x8c\xa1\x1c\x5c\xba\
-\x17\xb1\x1c\x1eX|>\x04\xeds\xec\xf0\xb5\xb0;z\
-%\xd0\xcb3\x18_1D\x1f~\x89\xff\xac\xa8\xb3G\
-\xa2\xae\xef0\x03\xe3D+ \xc4\xf6jc)\x13j\
-(\xd4\x8e\x18b\x12\x96m\xde?\xd3f|Kd\x0a\
-\xfe\x5c\xc8\xa4\xc5i\xb3\x06.1l\x07\x980\xf4U\
-\xe2R\xbf(.\xe3\x22\xe0I^%2%}v.\
-\xe7\x0dlZ\x89\xe7J\xa9}}\xc8\x14D\x9e\xf2\xc6\
-\xed\x95,\xfd\x8c\xc7\x90{U\xe2+D\xdd\xf9\xc2\xc4\
-\x7fuE+\x88:\xc3A\xe37E[\xe0\xf2|o\
-t\xff\xea\x8a\x16\x90y\xbe\xc0\xfd\x9b\xa2Uo\xda\xe6\
-d\xd4\xbdi\x9b\xf3!S\xbfi\x9b\xf3\xe1\xf2M\xdb\
-\x9c\x11\x99o\xda\xe6\x8c\xc8|\xb6\x80\x83\x87L\xa1\x12\
-*\x99\xb2|\xe4.B\xbeN\x1e7/ /kD\
-\xc6\x94\xe3\xcb\xce\xd7\xc9\xe1\xe6\x05\x22\x8a\x1e*\xad\x82\
-RA({\x95\xb8<\x9f9\xb9\xdf&\xf2\x90\xa9\x11\
-?\x8a\xda\xd7\x89\xcc\xf3\xbd7\xe8\xd8\xe61\x1e\x1d\x02\
-\xe98\x8a\x0d\xae\x14P\xc8_#\x0a\xcfx\x94\x9a$\
-\xdc\x08E%7m\x5c\xeaDZ\xa6\xa5\x10#\x87\x1e\
-\xf2:5\xce\x19\xcf`\x0eAeI\x97\xe65\x1aB\
-\x94\x9c\xd3\xaa\xdc\x87Lf\x12\xcb$\xfc\xbcf\xba\xa4\
-\xe4\x9c*\xe70*_9]>\xff\xab\xea\xbf\x8c\xb7\
-C\xe99\x95\xcf_\xdc\x0f\xa7\xf4\xd8\xf3'o\x01\xa2\
-\xfd\xb8|\x8b\x5c\x9e\x0f\x99\xec|\xef\xfdi\xd2\xc5\xa2\
-I$\xe7\x94Z\xf3\xaa\x83\xe9\x94\xfde_\xf8S~\
-,\x01\xbd\xd8\xc9\xba:O\x14\xe8\x16w\xbfiD\xbe\
-\xe5Q:\xc0\xd5\xf9b5!f\xa3\x0c\xd9\x8dP\xf6\
-R\xcc\xf6q\x8cY?\xddS\x95\x17\x15\xf3\x94N\xbf\
-\xcc\xb3\x87w\x15\x1a\xae\xd2jIw\xe9u\xe6N\xcd\
-\x02\xf2\xf2\x1b\x1eE\xc5\xd5j=\xcd\xd6e\x95r?\
-\x8d\xaa\xe2`m\x9d\x89\xd5\xdb+\xec\xb5\xaa'\xe1\xfa\
-\xcdM:]=|\xba`\xedJL\x8a\x0a\x0bk\x17\
-\xe3\xd5\x0b\xa1\x13\x0b\x9ec\xa7\x09^\xc0\xd0\x98F\x16\
-\xdc=\xda\xae\x9c\xae&\xf7\x98\x1f8\xbe\xcf\xb7\xf6n\
-\xd7i~\xbf^#\xc0\x22}\xcc\xd6\xcdl\xb5u>\
-[c\xaa\x86E\xc6[\xafds\xb3z\xc8\xd1\x82d\
-~\x9f\xb5G\xc0z\x7f\xd1\x1e\x0cV]\xafq[B\
-\x0d\x1f\xe6Kh\x10\x979v\xa9\xec\xac\xbd\x80(\xa7\
-\xa9M\x07s\x05\x04\xe0O\x8a}\xcd\x1f\xf1^\xbe?\
-\xa3\xfb\xf94\xdb\x84\xe7\xe4\xea\xe2\xab\xab\xd5.\x5c\xbf\
-\xba\xfa?`\xd4\xf8.\xdd\xde@\x0f\xb3t\xb1\xd9\x07\
-\xb2\x5c\xb9A|\x90\xbcf\xbbZd\xc0b\x93\xac>\
-\xeb\x8d8\xf2\x8bM\x83\x1a\x8b\xad\x0b\xe2~\x99\xde\xc5\
-\xd7\x8b\xd5U\xba\xe8\xc5\xf1m\xba\x9b\xdf\xce\xbff\xd3\
-\xfa(}\xb3\x0fo\xc5\x85\xc8\xaaQ\x02\x93+\xd9r\
-\xfb\x88Y\x94w\x8fX\xd6\x90>X\xc0\x84\xa8-O\
-\xcc\xa6<_^\xef0\x83\x05\xf2WENU\xd5c\
-\xa0*\xbb\xbd+jk\xe6\x89\xa2/\xf3\xcd\xfc\x0a\x0f\
-\xc2{+\x04\xd8%\xe6\x1e\x9e\xb6Jq5\x05<\xce\
-\x09\xa5\xe2f\xb5\x5c<\x16`\xa5,\xe9\x8a\x10W~\
-\x9bm\xd3i\xbaMkyR\x96p\x90\xa8%j\xd6\
-\xd3\xd9\xe5?\x7f\xf8\xb1:\xe3?\x99\x5c\xfe{\xb5\xfe\
-\xa3\x9cB\x14!@z\xb5\xba\x07\x9a\xad.=`\x12\
-\xe3\xc9%\xca\xd5t\xfby~\x0b\x0c\x83\xa9\xb1\xff{\
-w\xbb\x00\xc9VU4\x80\x11\xdbu\xa7y\xb7\xeb,\
-O}\x1d\xcc\x16>\x9d\xdc\xce\xb1\xd1\xf8_\xdb\xf9b\
-\xf13\x0e\xe2\xddE(:\x9do\x17\xd9g7f\xfe\
-X\xaeb\x5c,\xa3\xbcI\xe0\xad\xf2\xe3\xb8D\x83\xfb\
-t]\xa3\xe7Z\xab\xeav\xe86\xa4\x0eM\xa2\xf16\
-'S\xa3\x18\xf3yf\xb1z_\xa2\xf1\xba\xa2\xaaP\
-xA\x08\xa6\x18z\x1a\xa0}\x0cxj\x98\x01\x8bY\
-\xc9a\xc0\x91\xab\x96V\x13\xcc\x13Jt\x02\xda\x87\x83\
-\xed,y\x22\x89\xf0#\xdc\xf9\x14%\xf1R\xe0\xac\x81\
-\x05k\xa4\x167,\xea\xf4fVSB\x85d\x1ff\
-\x80\xc1K\xc0\xed\xf7-\xc5\xebr\x17\xbfw\xd5\xde]\
-\x99\xcdv\xbd\xfa#\xbb\x5c\xae\x965)\x16\xf7\xf2`\
-<-\x94\x7f\x83\xa5\x90x\xad\x1b\x99\xb58\xc6$\x22\
-.\xd7\x97W\xe7rIX\xc0\x00o\xe4\x87\x03\xba\x8e\
-\xa5H\x80\xf5t\xa3\xab\x10J5\x81\xb5\x81\xa6\x1ey\
-\x8fq\xb8\x98\xf8\xd6K\x07i8(\xa8+\x85\xf1\x9f\
-\xf6\x14U\xa2\x98R*\xb0*\xeeR\xbd\xb2\xc6\xfd\xa4\
-R\xf6c2*\xc5;7\xa3s\xdc\xe9@\xce\xbd\xbe\
-\xddQ\x03w\xe7\xcc8B\x9d\xe0\xcd\xb3\x140\xb9\xc8\
-L\xd7\x93\xbeE\xe0\xec[\xa9a\x8f 1\x1cY\x0b\
-\xd3\xb8$U\x0e\xefn\xe7KD}\x83\x9c\xeaz\x97\
-\xc1\xd5\x09b\x13\xaa_\xef\x02\x84Z\xd7>\x06jQ\
-jFTj\x8c\x0b\x88Q\xd9y4\x8901\xad\x15\
-R\xc8\x08d\x017 \x18Fy\xe3(\xce\xffV\x1f\
-s8`\xf4\xaa\xa6lQ\x17\x14\xb0\xb0\x0d\xd5\xbfE\
-TT\x92\xe8kh\xba\x9bm\xban\xdf&+\xeb\xb2\
-%\xcc\x9b'TP\x8c\xab\x9f\x8fL\xd0\x1d\xa0\x84\x80\
-C\x10\x03sh0\xe3\xa4\xed\xe1\xad\x93\x04\x92%G\
-\x0b$\x1b\x10Hn\xa3\xa4\xd9\xcb\xbb\xfe]\xdf^\x89\
-\x14\x10\x0e\xe7d\xb6\x8f\xe3\xeb\xe2\xc1\xe7\xb9\xee\x084\
-\x91\xda\x12\xa6\xc0\x17\xc3\xc4\xba\x8c\x0b\xc5p\x80\xea\xb9\
-\x06\x88a%\x12s\x01\x80\xc2\xe1\x12<\x1b\xc6\xbc\x10\
-LN\xd1\xa0h\xb8flT\xe5du$Mq\x8b\
-$\xa5\x22\x8aMb@'\x19\xd0Te\xd2\xd5(.\
-\x1e\x1bEe\x0b$\xef\xaa|T67\x8d\xc2\xba\x1d\
-\x19\xd5-\xa3\x12\xd6\x07\x08\xb6\xf2\x07+\xe7R\x0d\xd4\
-\x9d\x5c\xcd6\x0d\x1e\xeff\x91m\x08\x88\x9e\xeap\x12\
-\xdb\x86xj$\xbd\xad\xe4\x99\x9fI\xf9\xb0\xbc\x04\xa5\
-?\x84\x03\x02R\xb9\x22\xaa\x1es\x04\xdc@%-\x11\
-.9\xa7\xa2`b(G\xa9\xd5s\x0d\x10S\x8e\xc9\
-9\x15\x03\xd3D\xa9\xc4p\xa2E\xc7 !\x0a\xd3\xff\
-\x0c\xd3\x1c\xb5_\xe1.\x88\xfa\xcc\x5c\xd6 \x1a\xee\xc1\
-\xd7\x88\xf1\x8e\xb9\x00S\x88\x89\x10\xd8j=\xbf\x9e/\
-\xd1S\xf8%\xa2\x86\xe2\x97\x0c\x80<u\xb9\xa8`\xba\
-\xd1?\x22\x0a~\xb8\x02\x863u\xa1\xcb\xb1\xee\xe0\xa4\
-J\xac\xe1\xc0/^\x99\x16u\xdb\xaa\xd0b\xae\x0e\x03\
-\xce\xaa\xd7\x1f0q\xd9a5p]\x06\xad\xadM\xc0\
-\xc4\x13\xcc+ex\x92\x862\xbf\xc3\xaa\xc8\x1b\xb8*\
-\xf3&X\xf5V\xaf\xa3\xbb\xde\xafQ\x03\x0d\xb2x\xc0\
-\xc9\x00A\xc2s]\xc6\xd0@q\x8d\xa4I\x84T\x1c\
-8\xa5.kL\xa6,\xb4$1(PL\xdd\x1d\x05\
-\x89\xe1/_8\x94KP9\xdc\xe4\x95\x92\xf9\xed\xe0\
-\x93\x8f`\xf8X\x8f^\xb5\xab\xe6\x18X\xca\xd7h\xb8\
-\xcd\x81\x19q\xfbX\xe8C\x9e\x88&oZ'&}\
-\x1f2E0+R\xdb\x1c(g7\x12\xa0cA\x1a\
-\x80\xec\x8c1!\xbd\xb1\xb9\x9a\x07\xae\x11\x0a\xcaGT\
-$D[N\x94WV>\xa0\xb8-\xda\x00\xb6r@\
-Z\xd7v\xe1\xbd\x11\xb0\x0c\xc7\x8f];\xa3@\xfcU\
-E^\xffnR\x96\x10\x85\x82\x1a ]\xe6\xa3\x1a \
-\xee\xb6\xf9\x1a\xdd\xe2\xbc\x12\xdc\xa6\x09lL\x82\xe9\x91\
-ARD\x0c\xb3t#,R\xa8\xa2\x04i\xba,*\
-\x1f\xb0e\xde\x02j\xdd\xd91Ex^\x8d\xa35\xe0\
-\xb1\xc0\x01s\x87\xb1\xbc(?pf\xa9\x22\xb4.*\
-\xa0q5\x0e\x9e[`\x0a\x04s_\xa7P\x8d\xed\x83\
-\xe7\x04s@a\xc30T\xa3\xd7\x95G\x03\xab\x8fT\
-b\xde2\xc9\xe8H%L\x1a\xe2\xbe\xaaa\xafi\x1c\
-\xea\xd9PM\x99\xa6\xb6\xe8\xb9\xfa\xc8\x81Z`i\xb0\
-\x070\x7fp#\xad\xd5\xef{h\x0b\x5cL\xcb+\xe2\
-\xb2`\xe6hG\x5c,A.B\xda\x92\xb0b.\xea\
-\xa2\xe2oNY\xd8@\xa9\xa8\x04\xab*\xdb\xc0^\xdf\
-X\x84\xe2\xc7\xd1\x954\xa0\x89\xb8WV\xf7^\xcc\x07\
-\xd4\x81\xa3+L\xe6m\xea\xfa\xb8\xdb$'+\x0e\xa8\
-\xc8\xe9\x0at\xa85\xd4\xd1\x15~y\x00\xd8\xd5 (\
-\xc0\xd91\xc5g\xf7\x7f\x5cF\x01\x88\xf4\x8b `p\
-\xba:\xd7O\x5c\xc3\xe6\x9f\x1d\xb4\x16\xd4\x11TQ\xea\
-\xd2-\x19\xc3\x0d\xc8,\xaf\xb0j\x84\x8b)\x9a\xf1(\
-\x07\xa5,\xaf\x97Q\x13\xbeIR\xb5\xafB\x02\x09\x1d\
-j\x93W\xe2\x11\x1a\xe0\x98\x0f{\x85\x95 \xbd\xfa>\
-$\xac\x04m\x0a\xab7\xad\xf8\xa6\x15\x036\x14&\xfa\
-\x07\xa5bI\xd0\x1b\x0e\x9bd{%\xdd!\xf1\xa4Y\
-G:I\xbeW6i\x16\x15 \xfd\x82\xc9\xf5\xda\x92\
-K\xd2*\xd1#\x97\x94\xe4\xaa\x90K\x82\xc8\xa3\xe5\x12\
-\x88\x98\x86XB\xfe\x0d\x89%0\x91K\xb1\x04*\xef\
-\x90X\x02\xe9\x16\x10K\x8ah\xd6+\x96$\xd5&\x17\
-K\x92\xcb\xa3\xc4\x12k\xf8\xbe\x87#Mvp\x1c\xf0\
-M\xd8\xbc\x09\x9b\xb0\xb0Q\x5c`\x16\xc43\x08\x9b\xa0\
-\xdb\xca)\xd8g\xbc<\xbcS|\x8ae\x82\x01 \xab\
-\xac\x0b\xab)M4\x97}f\x15lo%\xb5\x18\xb8\
-\xb4\xb4\xb0\xd8\x99c)\xea\xde\xde2\xc1\xbd\xb2\xf2!\
-\x97]\xd8\x06\x0c\x9f\x12\xb0\xae\xed\xc2{#`Yn\
-\xdf\x82\xd5\xc7\xd1\xae\xca\x0b\xbc\xbe\x8b\x09\x19\xa9\x9d\xf1\
-\x0c\xc6\x9b\xb5\x1e@\xdcnQ\xda\xea\xa5\xa9.\x0dJ\
-.\x8eiM\x8b\x95\x08\xc1\x98TuQ\xf9\x90\x1b\xea\
-`\xe0Y+\xdcX\x02_\xb1\xbb\xea\x5cP\xfa\x0d\x5c\
-I\xde\xbd\xcdE|^\xe8\x16#@\xce\x00\x87\xd4e\
-e\x8b\xdc\x5cwmh\xe4\x00yQ\xeb&\xd0\x80w\
-%a!f\xfbm+j\xa1\xa9\x11\xfbm+60\
-\x96\xf2&\xd6\xde\xc4ZX\xaca\x0c\x97\x11\xdb\xf8\x92\
-\x9ds\x1aQV\xd5\x01\x04\xf0\xc2\x88.\xc4Q\x19?\
-\x00\xebM0U\x17\x15\x7fsY\xe4\x1a\xb8\xe8\x01u\
-\x01\xbb\xb2\xb2\x0d\xec\xf5\x8dER\x15\xb6\x14\xb4\x82f\
-^Y\xdd{1\x1f!s\x1f\x8fJKM]\x1fw\
-\x9b\xe4\xe2\x88\xe5\xec\xef\x04\x12\xac\x90\xe9<v\xa0r\
-\x81\xc4\xa0GpX\x8b\x82\xfcO.\x8c\x10V)'\
-\x8c\x00\x88SW\x99\x9bm\x1e\xb4,\x85\x11\x80+[\
-\x04\x0e\xca\xe5@KC$vR\x17V\x8dry\x84\
-\xcd\x8c\x88rPkFE\xdfQ\xb3\xc1^i$\x8f\
-{yg{_\xde\x05\x83PZ\xbc\xf9uo2i\
-\x80L\xe2L\x18\xab\x1a\x99\x1bO\x95IO\x88\xd1\x83\
-\x19\x06\xfcl\x1a\xaf\xc8\xdf\x88\xf6\x8dhC\xe2\xb1e\
-\x99q\xdb{* \x18\xf5b\x22\x18\xa2\xe7\xb6?D\
-\xaf\xbd\x18=\xb1\xc08\x85\x15k\x8bx\xb6\x11\x92P\
-]\x17\x15\x7fs\x15\xeb\x1a\xf0\xa8\x00cUe\x1b\xd8\
-\xeb\x1b\x8b*\x0b\xd9\x05\xa3\xa9WV\xf7\x9e\xcf\x87\x83\
-\xfb\xe2\xf4\x9e\xa1\x5c\xeb\xba>\xee6\xc9U,\xc9c\
-\x17N\xc5j\xed\x8e\xe0c\xf7\xc5b\xa4\x95\xda\xc8\xb2\
- \xff\x93\xabX\x84\xa5y`^\xe2k\x04\x8e\xf9_\
-K{\xbf\x00\x16\x95\xb9\xaf\xdd\xb7$\xb8:Q-\x06\
-\xfe*)\xfc\xc2\xaaM\xae`\xa1\x95\xb4*r\xa0\xf8\
-u\x9bE\xd7Q\xa3\xc1\xa0\xe8\xbc\xe4\x92\x19U\x9e\xd5\
-\xad>\x02E2%-\x87\x8dH\x84\xb2Bks\xe8\
-]z}<n5\xcdP\xc6\x81\xe4\x9al6\x9bz\
-\x0a\xf5{Z]\xbf\xbcut$q\xde\xd2\xc2\xbeP\
-\x86\x5c\x05\x93p\x84\xc4A\xf0I|w\x81\xe9\xfe\xf1\
-\xdb\xc9\xc1\xe8\xd0\x98\xed_\x82GH\xf1\xd5\xa5\xa4R\
-\xe5\x85V\xa2\x9fJQ^\x19\xcd\xc0\xb1D\x97\x87q\
-;R\x89\xa0Z\x08\x8d\xf6\x9b\x00~\x80Q,\xb8b\
-\xf0\x181\x09\xe4\x80\xa77\xa0\x04\x89\x13\xfc4\xfc\xca\
-^\x18\x0a\xdf\xff\xc38`\x12\xe2\xa1eK\x0cb\x99\
-&\x86q\xad8\x96)F\x8c\xc6;\xd2\xb0\x19\xe0\xfe\
-q\xe0e\x0d\xcf\xb0\xe30]&\xf0\xdb\x09\xd0\xa8S\
-`zJ|\xbd\x0f\xf2\x89\x80\x01\xa7\x82k\xf5^\xa1\
-\xf7\x9b;\xf8\xc5\x0a\x83<-\xef\x9c\xf8r\x99M\xb6\
-\xabu<\xb9_\x7fI\xb7\xf7\xeb\x0cO\xb3T{y\
-\xf08D\x11\x08\x90\xee\x90\x83\xb5\x96\xa0\xbb\xec\x0e\xe8\
-hMX\xeb\xc0\x83\xbb1N9\x80TI\xdd\xbdC\
-<\xde)\x9eC\xc7xd\xe0\x1cO\xe8 O\x05\x1f\
-U\x1d\x97\x95-X\xaf\xe3\xa2\xa6\xea\xb69\x85=\xe7\
-\x19Zg\x96\xfaN;5N2t\xb3\xdb7N2\
-tS\xe2\xd7\x02\x97\x926]xN9\x13@\x96\xb4\
-\xe7\x85\x07\xa7\xc3\x0e\x84\xf5\x1dp\x082x\xf7x\xda\
-)\xb3c\xc3B\x0656\x18\x19\x8a\xc1\xa1\xf8\xef\xdb\
-\xba\xc0\x96\xbfB\x0a\x0f\x9e\xbf\xc5oQ\x91\xa0\x86\x8d\
-\xc5\x10<\x88\x7f\xa6\xaa\x1c\xcf\x85\xeco\x9c\xe7\xe5\xb6\
-\xfa\xfe\xe3\x0e!\x80'JE\xfdm\xa4\x8d\x93k\xb8\
-98#\xcf\xdf\xdb\x15W8\xbc4\x9d\xe5y\xb2\xfc\
-\xa4\x19ltUS\x1cA\xe3x/\x13\x0c\xc4\xd6\x97\
-\xf7\xc2@\x9c\x8a\xce\x81\xa0zj\x86\xba_N\xca\x9f\
-\x9cX\xbf\x9b\x11\xf7\xcd\x1e=\xb4Y\x7f\xf3\x8b\xb7\x1a\
-\x0f\x95 y\x17x\xabg\xe4\xddo\xecbF1#\
-\x019\xc7\x0f\xdfY\xa6\xf5\x0e\xef4\xce\xe5Y\x0f)\
-%\x1e\x8b\x83\xb3^\xcd\x0e\x8f\xdf\xb5\xb0\xfe\xe8\xdf\xbb\
-\x09\xae\xf71x3\x07\xba\xd2x\x97\xc9\xf8\xe9\xee\xf7\
-\x0f\xbdw\xb6\xde\xdaz\xb6\xb0\xc0!+QH\x8f\xc6\
-\xe1\x9e]k\x12{\xbd\xec\xce\x0c\x94\x90\xd4\x82kV\
-\x0c\xccg23\xd3\xe6\xc0\x04\xac\x02\x90^J\x05&\
-\xe0Qj)\xdd\xf6Puu\xa1\x05u0`\xb7\xc4\
-y\x87c\x02;\xe7- \xb0k\x9d\x1e\xca\xa1\x9c\xb4\
-\xa05\xc7\x95'\xaf]\xb6\xa2\xee\x02\xc4>\x19\xd0\xc4\
-Q\xc0\xaa\xc1\x0b\x8a\xbd\xca\xa0\xb3\x8c=cX\xd37\
-\x06\x1d\xa0pj\xba\xab\x96X.[$\x86\x83\x91\xc9\
-[Xj\xcb\xa5\xe37\xa4\x09\xee\xb8\xb1!\x16\xf7\x8d\
-TL\xccQ\x84\x86\xff\xbaK\xd0O\xd8\x92A\xd6C\
-\xc0\xa7\x18!\x07\xe5\xfe\xc4\xfb\xeer\x0f5x\xc2|\
-\xe5Q\xdb+\x0e`\xb1\xc1\x04l\xef\xdex\xdb\x17\xda\
-\xda\xb84\x17\xcc\xc1\xddm\x0ctpk\xabkS'\
-\xa1j\x88\xe9\xb5g\xa7\xe2\xa3\xf76>\xc3\xe6\x12{\
-\xdc\xe6\xdaa\x9b\x1b\xe0\xdd\xee\xfez{\x18\xdc\xe2\xfc\
-&js\x8b\xdb2v\x9f\xf4\xf6E*\xab\xf5_\xb9\
-\x12A*\xb5\xb0O\xe2\xb1\x135\xcfy\xb6w \xe7\
-J\x22\xf6o.\x19\xf4\xf2\xd0C\x89\x0a o\x80T\
-vN9\xf3\xa4\xb2D\x7f\xd6\x04\x18\xf7\x04\x0a%f\
-\xc8}\x8az\x11\x92\x9c&~\xca9W\x8b(V\xb5\
-G\xb5\xd4\xb5{z8Q\xb7\xc0\x02\xd8\xe9\xecL\xb4\
->N\xdd?M\xb2\x94V\xc1\xc9\xd6\x19\x90\xa8\xe8g\
-\xd8\x1e\xeb,\xc6o\x8cT\xc6\x17(\xb5\xc4\xe8\x11(\
-\xc2\xef\xa4I\xbb\x076-h\xa0\xc1\x1a\xd4Sx\xf4\
-Tk\xa0W\xa4<\xb6\xc9q\xd7v\x09OZ*%\
-\xfdR\xb3w\xa9\x94\x0c\x89\xb0\x1d\x10\x86\x03\x85\xe70\
-\x02>0\xdd!w\x17=\xd4\x84T\xcf\x10\x9b\xb6\xa3\
-\x16k2=\x8by\xce\x8f1\xcf\xc1\x9a\xd7\x03\xd6\xd1\
-\xf6`v\x01\x8b,\xe0\x11\xf5;\x85\x87\x9c\xa9\xce\x08\
-\x87h\xb8\xe5Xxk\xb4O\xa0\x0b\xce\x8f#\xe3\xde\
-\x95v&\xa0\x8d\x0b^\x1c\xebp\xd7k\xab\xbe\xf1\xcc\
-\xd74\x9e\xe4l \xcd\x13\x0f\x1d\x05X\x8aW\x9c\xf3\
-G\xbc\x1f\xff\xf9\xdd\xff\x03\x0b\xb0\x0a\x0c\x99\x9b\x00\x00\
-\
-"
-
-qt_resource_name = b"\
-\x00\x05\
-\x00o\xa6S\
-\x00i\
-\x00c\x00o\x00n\x00s\
-\x00\x06\
-\x07\x03}\xc3\
-\x00i\
-\x00m\x00a\x00g\x00e\x00s\
-\x00\x16\
-\x02\x1b\xe1\x0a\
-\x00g\
-\x00o\x00-\x00n\x00e\x00x\x00t\x00-\x00v\x00i\x00e\x00w\x00-\x00p\x00a\x00g\x00e\
-\x00.\x00s\x00v\x00g\x00z\
-\x00\x11\
-\x04\xf3\xa4*\
-\x00g\
-\x00o\x00-\x00n\x00e\x00x\x00t\x00-\x00v\x00i\x00e\x00w\x00.\x00s\x00v\x00g\x00z\
-\
-\x00\x15\
-\x01\x09v*\
-\x00g\
-\x00o\x00-\x00p\x00r\x00e\x00v\x00i\x00o\x00u\x00s\x00-\x00v\x00i\x00e\x00w\x00.\
-\x00s\x00v\x00g\x00z\
-\x00\x0d\
-\x0e\xb9\xa6*\
-\x00z\
-\x00o\x00o\x00m\x00-\x00o\x00u\x00t\x00.\x00s\x00v\x00g\x00z\
-\x00\x12\
-\x0al\x90\xca\
-\x00d\
-\x00o\x00c\x00u\x00m\x00e\x00n\x00t\x00-\x00o\x00p\x00e\x00n\x00.\x00s\x00v\x00g\
-\x00z\
-\x00\x1a\
-\x01d\xbbJ\
-\x00g\
-\x00o\x00-\x00p\x00r\x00e\x00v\x00i\x00o\x00u\x00s\x00-\x00v\x00i\x00e\x00w\x00-\
-\x00p\x00a\x00g\x00e\x00.\x00s\x00v\x00g\x00z\
-\x00\x0c\
-\x009l\x8a\
-\x00z\
-\x00o\x00o\x00m\x00-\x00i\x00n\x00.\x00s\x00v\x00g\x00z\
-"
-
-qt_resource_struct = b"\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x10\x00\x02\x00\x00\x00\x07\x00\x00\x00\x03\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x010\x00\x00\x00\x00\x00\x01\x00\x00\xba\xe2\
-\x00\x00\x01\x81\x8a\xd9\xf0\x94\
-\x00\x00\x00|\x00\x00\x00\x00\x00\x01\x00\x00J'\
-\x00\x00\x01\x81\x8a\xd9\xf0\x94\
-\x00\x00\x00\xf6\x00\x00\x00\x00\x00\x01\x00\x00\x89\xa4\
-\x00\x00\x01\x81\x8a\xd9\xf0\x94\
-\x00\x00\x00\x22\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x01\x81\x8a\xd9\xf0\x94\
-\x00\x00\x00T\x00\x00\x00\x00\x00\x01\x00\x001K\
-\x00\x00\x01\x81\x8a\xd9\xf0\x94\
-\x00\x00\x00\xcc\x00\x00\x00\x00\x00\x01\x00\x00x\xec\
-\x00\x00\x01\x81\x8a\xd9\xf0\x94\
-\x00\x00\x00\xac\x00\x00\x00\x00\x00\x01\x00\x00c\xbc\
-\x00\x00\x01\x81\x8a\xd9\xf0\x94\
-"
-
-def qInitResources():
-    QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
-
-def qCleanupResources():
-    QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
-
-qInitResources()
index e4215769b24e3d392b8346e6292d957d9742b745..9ed525dbf13b526919a75b1bff17b6d06b2780f1 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'mainwindow.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -21,7 +21,7 @@ from PySide6.QtWidgets import (QApplication, QHeaderView, QMainWindow, QMenu,
     QMenuBar, QSizePolicy, QSplitter, QStatusBar,
     QTabWidget, QToolBar, QTreeView, QVBoxLayout,
     QWidget)
-import resources_rc
+import rc_resources
 
 class Ui_MainWindow(object):
     def setupUi(self, MainWindow):
@@ -123,7 +123,7 @@ class Ui_MainWindow(object):
         self.splitter.setOrientation(Qt.Horizontal)
         self.tabWidget = QTabWidget(self.splitter)
         self.tabWidget.setObjectName(u"tabWidget")
-        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth())
@@ -152,7 +152,7 @@ class Ui_MainWindow(object):
         self.splitter.addWidget(self.tabWidget)
         self.pdfView = QPdfView(self.splitter)
         self.pdfView.setObjectName(u"pdfView")
-        sizePolicy1 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
         sizePolicy1.setHorizontalStretch(10)
         sizePolicy1.setVerticalStretch(0)
         sizePolicy1.setHeightForWidth(self.pdfView.sizePolicy().hasHeightForWidth())
@@ -179,7 +179,7 @@ class Ui_MainWindow(object):
         self.mainToolBar.setObjectName(u"mainToolBar")
         self.mainToolBar.setMovable(False)
         self.mainToolBar.setFloatable(False)
-        MainWindow.addToolBar(Qt.TopToolBarArea, self.mainToolBar)
+        MainWindow.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.mainToolBar)
         self.statusBar = QStatusBar(MainWindow)
         self.statusBar.setObjectName(u"statusBar")
         MainWindow.setStatusBar(self.statusBar)
index 9337ad2ab9a0bc90f2fe52f21aa8630d9781efc7..16924cdcd064c160c040b1f24c1f465922727b52 100644 (file)
@@ -75,11 +75,11 @@ The class contains a member to store the celebrant object, and also a
 list member storing the Person instances.
 
 In QML, the type of a list properties - and the guests property is a list of
-people - are all of type ListProperty. ListProperty is simple value
-type that contains a set of functions. QML calls these functions
-whenever it needs to read from, write to or otherwise interact with
-the list. In addition to concrete lists like the people list used in this
-example, the use of QQmlListProperty allows for "virtual lists" and other advanced
+people - are all of type :class:`~PySide6.QtQml.ListProperty`.
+``ListProperty`` is a simple value type that contains a set of functions.
+QML calls these functions whenever it needs to read from, write to or otherwise
+interact with the list. In addition to concrete lists like the people list used in this
+example, the use of ``ListProperty`` allows for "virtual lists" and other advanced
 scenarios.
 
 Running the Example
index 90cb41107c79ab785701bf056be403c5dee5edaf..a98f18c8115d4101c712ca3e300891892e586474 100644 (file)
@@ -15,8 +15,9 @@ have a ``slices`` property that accepts a list of ``PieSlice`` items:
    :lines: 4-32
 
 To do this, we replace the ``pieSlice`` property in ``PieChart`` with a
-``slices`` property, declared as a class variable of the ``QQmlListProperty``
-type. The ``QQmlListProperty`` class enables the creation of list properties in
+``slices`` property, declared as a class variable of the
+:class:`~PySide6.QtQml.ListProperty` type.
+The ``ListProperty`` class enables the creation of list properties in
 QML extensions. We replace the ``pieSlice()`` function with a ``slices()``
 function that returns a list of slices, and add an internal ``appendSlice()``
 function (discussed below). We also use a list to store the internal list of
@@ -31,13 +32,13 @@ slices as ``_slices``:
    :lines: 75-79
 
 Although the ``slices`` property does not have an associated setter, it is
-still modifiable because of the way ``QQmlListProperty`` works. We indicate
+still modifiable because of the way ``ListProperty`` works. We indicate
 that the internal ``PieChart.appendSlice()`` function is to be called whenever
 a request is made from QML to add items to the list.
 
 The ``appendSlice()`` function simply sets the parent item as before, and adds
 the new item to the ``_slices`` list. As you can see, the append function for
-a ``QQmlListProperty`` is called with two arguments: the list property, and the
+a ``ListProperty`` is called with two arguments: the list property, and the
 item that is to be appended.
 
 The ``PieSlice`` class has also been modified to include ``fromAngle`` and
index 6c934ec896feb94ec7f08195d3e8493fc657c213..d501bbdb4646185fc0558d2a6c915b3872216652 100644 (file)
@@ -23,5 +23,6 @@ if __name__ == '__main__':
     if not engine.rootObjects():
         sys.exit(-1)
 
+    ex = app.exec()
     del engine
-    sys.exit(app.exec())
+    sys.exit(ex)
index 3987acc9e3935319c5115a1a93c55449acdeca93..7f7798ed8dd983d7c5dd076df408db9f334a1854 100644 (file)
@@ -6,47 +6,68 @@ import QtQuick.Controls.Basic
 import QtQuick.Layouts
 import FileSystemModule
 
+pragma ComponentBehavior: Bound
+
 ApplicationWindow {
     id: root
+
+    property bool expandPath: false
+    property bool showLineNumbers: true
+    property string currentFilePath: ""
+
     width: 1100
     height: 600
+    minimumWidth: 200
+    minimumHeight: 100
     visible: true
+    color: Colors.background
     flags: Qt.Window | Qt.FramelessWindowHint
-    title: qsTr("Qt Quick Controls - File System Explorer")
+    title: qsTr("File System Explorer Example")
 
-    property string currentFilePath: ""
-    property bool expandPath: false
+    function getInfoText() : string {
+        let out = root.currentFilePath
+        if (!out)
+            return qsTr("File System Explorer")
+        return root.expandPath ? out : out.substring(out.lastIndexOf("/") + 1, out.length)
+    }
 
     menuBar: MyMenuBar {
-        rootWindow: root
-
-        infoText: currentFilePath
-            ? (expandPath ? currentFilePath
-            : currentFilePath.substring(currentFilePath.lastIndexOf("/") + 1, currentFilePath.length))
-            : "File System Explorer"
-
+        dragWindow: root
+        infoText: root.getInfoText()
         MyMenu {
             title: qsTr("File")
 
             Action {
                 text: qsTr("Increase Font")
                 shortcut: StandardKey.ZoomIn
-                onTriggered: textArea.font.pixelSize += 1
+                onTriggered: editor.text.font.pixelSize += 1
             }
             Action {
                 text: qsTr("Decrease Font")
                 shortcut: StandardKey.ZoomOut
-                onTriggered: textArea.font.pixelSize -= 1
+                onTriggered: editor.text.font.pixelSize -= 1
             }
             Action {
-                text: expandPath ? qsTr("Toggle Short Path") : qsTr("Toggle Expand Path")
-                enabled: currentFilePath
-                onTriggered: expandPath = !expandPath
+                text: root.showLineNumbers ? qsTr("Toggle Line Numbers OFF")
+                                           : qsTr("Toggle Line Numbers ON")
+                shortcut: "Ctrl+L"
+                onTriggered: root.showLineNumbers = !root.showLineNumbers
+            }
+            Action {
+                text: root.expandPath ? qsTr("Toggle Short Path")
+                                      : qsTr("Toggle Expand Path")
+                enabled: root.currentFilePath
+                onTriggered: root.expandPath = !root.expandPath
+            }
+            Action {
+                text: qsTr("Reset Filesystem")
+                enabled: sidebar.currentTabIndex === 1
+                onTriggered: fileSystemView.rootIndex = undefined
             }
             Action {
                 text: qsTr("Exit")
                 onTriggered: Qt.exit(0)
-                shortcut: "Ctrl+Q"
+                shortcut: StandardKey.Quit
             }
         }
 
@@ -56,134 +77,109 @@ ApplicationWindow {
             Action {
                 text: qsTr("Cut")
                 shortcut: StandardKey.Cut
-                enabled: textArea.selectedText.length > 0
-                onTriggered: textArea.cut()
+                enabled: editor.text.selectedText.length > 0
+                onTriggered: editor.text.cut()
             }
             Action {
                 text: qsTr("Copy")
                 shortcut: StandardKey.Copy
-                enabled: textArea.selectedText.length > 0
-                onTriggered: textArea.copy()
+                enabled: editor.text.selectedText.length > 0
+                onTriggered: editor.text.copy()
             }
             Action {
                 text: qsTr("Paste")
                 shortcut: StandardKey.Paste
-                enabled: textArea.canPaste
-                onTriggered: textArea.paste()
+                enabled: editor.text.canPaste
+                onTriggered: editor.text.paste()
             }
             Action {
                 text: qsTr("Select All")
                 shortcut: StandardKey.SelectAll
-                enabled: textArea.length > 0
-                onTriggered: textArea.selectAll()
+                enabled: editor.text.length > 0
+                onTriggered: editor.text.selectAll()
             }
             Action {
                 text: qsTr("Undo")
                 shortcut: StandardKey.Undo
-                enabled: textArea.canUndo
-                onTriggered: textArea.undo()
+                enabled: editor.text.canUndo
+                onTriggered: editor.text.undo()
             }
         }
     }
-
-    Rectangle {
+    // Set up the layout of the main components in a row:
+    // [ Sidebar, Navigation, Editor ]
+    RowLayout {
         anchors.fill: parent
-        color: Colors.background
-
-        RowLayout {
-            anchors.fill: parent
-            spacing: 0
-
-            // Stores the buttons that navigate the application.
-            Sidebar {
-                id: sidebar
-                rootWindow: root
-
-                Layout.preferredWidth: 60
-                Layout.fillHeight: true
-            }
+        spacing: 0
+
+        // Stores the buttons that navigate the application.
+        Sidebar {
+            id: sidebar
+            dragWindow: root
+            Layout.preferredWidth: 50
+            Layout.fillHeight: true
+        }
 
-            // Allows resizing parts of the UI.
-            SplitView {
-                Layout.fillWidth: true
-                Layout.fillHeight: true
-
-                handle: Rectangle {
-                    implicitWidth: 10
-                    color: SplitHandle.pressed ? Colors.color2 : Colors.background
-                    border.color: Colors.color2
-                    opacity: SplitHandle.hovered || SplitHandle.pressed ? 1.0 : 0.0
-
-                    Behavior on opacity {
-                        OpacityAnimator {
-                            duration: 900
-                        }
+        // Allows resizing parts of the UI.
+        SplitView {
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+            // Customized handle to drag between the Navigation and the Editor.
+            handle: Rectangle {
+                implicitWidth: 10
+                color: SplitHandle.pressed ? Colors.color2 : Colors.background
+                border.color: SplitHandle.hovered ? Colors.color2 : Colors.background
+                opacity: SplitHandle.hovered || navigationView.width < 15 ? 1.0 : 0.0
+
+                Behavior on opacity {
+                    OpacityAnimator {
+                        duration: 1400
                     }
                 }
+            }
 
-                // We use an inline component to make a reusable TextArea component.
-                // This is convenient when the component is only used in one file.
-                component MyTextArea: TextArea {
-                    antialiasing: true
-                    color: Colors.textFile
-                    selectedTextColor: Colors.textFile
-                    selectionColor: Colors.selection
-                    renderType: Text.QtRendering
-                    textFormat: TextEdit.PlainText
-
-                    background: null
-                }
-
-                Rectangle {
-                    color: Colors.surface1
-
-                    SplitView.preferredWidth: 250
-                    SplitView.fillHeight: true
-
-                    StackLayout {
-                        currentIndex: sidebar.currentTabIndex
-
-                        anchors.fill: parent
-
-                        // Shows the help text.
-                        MyTextArea {
-                            readOnly: true
-                            text: qsTr("This example shows how to use and visualize the file system.\n\n"
-                                + "Customized Qt Quick Components have been used to achieve this look.\n\n"
-                                + "You can edit the files but they won't be changed on the file system.\n\n"
-                                + "Click on the folder icon to the left to get started.")
-                            wrapMode: TextArea.Wrap
-                        }
-
-                        // Shows the files on the file system.
-                        FileSystemView {
-                            id: fileSystemView
-                            color: Colors.surface1
-
-                            onFileClicked: (path) => root.currentFilePath = path
-                        }
+            Rectangle {
+                id: navigationView
+                color: Colors.surface1
+                SplitView.preferredWidth: 250
+                SplitView.fillHeight: true
+                // The stack-layout provides different views, based on the
+                // selected buttons inside the sidebar.
+                StackLayout {
+                    anchors.fill: parent
+                    currentIndex: sidebar.currentTabIndex
+
+                    // Shows the help text.
+                    Text {
+                        text: qsTr("This example shows how to use and visualize the file system.\n\n"
+                                 + "Customized Qt Quick Components have been used to achieve this look.\n\n"
+                                 + "You can edit the files but they won't be changed on the file system.\n\n"
+                                 + "Click on the folder icon to the left to get started.")
+                        wrapMode: TextArea.Wrap
+                        color: Colors.text
                     }
-                }
-
-                // The ScrollView that contains the TextArea which shows the file's content.
-                ScrollView {
-                    leftPadding: 20
-                    topPadding: 20
-                    bottomPadding: 20
-                    clip: true
-
-                    SplitView.fillWidth: true
-                    SplitView.fillHeight: true
-
-                    property alias textArea: textArea
 
-                    MyTextArea {
-                        id: textArea
-                        text: FileSystemModel.readFile(root.currentFilePath)
+                    // Shows the files on the file system.
+                    FileSystemView {
+                        id: fileSystemView
+                        color: Colors.surface1
+                        onFileClicked: path => root.currentFilePath = path
                     }
                 }
             }
+
+            // The main view that contains the editor.
+            Editor {
+                id: editor
+                showLineNumbers: root.showLineNumbers
+                currentFilePath: root.currentFilePath
+                SplitView.fillWidth: true
+                SplitView.fillHeight: true
+            }
         }
-        ResizeButton {}
+    }
+
+    ResizeButton {
+        resizeWindow: root
     }
 }
index 05fc728e77f118f82f5699a00f41fab7b67efc2e..fec76fe67f724f2cda5fa90155577b4cc88d7fd9 100644 (file)
@@ -3,9 +3,9 @@
         <file>qmldir</file>
         <file>Main.qml</file>
         <file>qml/About.qml</file>
+        <file>qml/Editor.qml</file>
         <file>qml/Colors.qml</file>
         <file>qml/FileSystemView.qml</file>
-        <file>qml/Icon.qml</file>
         <file>qml/MyMenu.qml</file>
         <file>qml/MyMenuBar.qml</file>
         <file>qml/ResizeButton.qml</file>
index 5793a62cf8bae54b3d00f8f17dbc4989ee205cbb..97d8a3d7913ac1de8c415c1757336f8ca6b51e65 100644 (file)
@@ -1,5 +1,6 @@
 <RCC>
     <qresource>
+        <file>icons/app_icon.svg</file>
         <file>icons/folder_closed.svg</file>
         <file>icons/folder_open.svg</file>
         <file>icons/generic_file.svg</file>
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/icons/app_icon.svg b/examples/quickcontrols/filesystemexplorer/FileSystemModule/icons/app_icon.svg
new file mode 100644 (file)
index 0000000..5aae422
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill="#EBDBB2" d="M13.25 8.5a.75.75 0 1 1-.75-.75.75.75 0 0 1 .75.75zM9.911 21.35l.816.578C10.819 21.798 13 18.666 13 13h-1a15.503 15.503 0 0 1-2.089 8.35zM4 6.703V10a2.002 2.002 0 0 1-2 2v1a2.002 2.002 0 0 1 2 2v3.297A3.707 3.707 0 0 0 7.703 22H9v-1H7.703A2.706 2.706 0 0 1 5 18.297V15a2.999 2.999 0 0 0-1.344-2.5A2.999 2.999 0 0 0 5 10V6.703A2.706 2.706 0 0 1 7.703 4H9V3H7.703A3.707 3.707 0 0 0 4 6.703zM20 10V6.703A3.707 3.707 0 0 0 16.297 3H15v1h1.297A2.706 2.706 0 0 1 19 6.703V10a2.999 2.999 0 0 0 1.344 2.5A2.999 2.999 0 0 0 19 15v3.297A2.706 2.706 0 0 1 16.297 21H15v1h1.297A3.707 3.707 0 0 0 20 18.297V15a2.002 2.002 0 0 1 2-2v-1a2.002 2.002 0 0 1-2-2z"/><path fill="none" d="M0 0h24v24H0z"/></svg>
index b7bc0ac6f30a40f4796f5637c1aae419d1f84fd9..178bf03e44a0407fa5ba764dcf15d0c99c3ae281 100644 (file)
@@ -7,53 +7,87 @@ import FileSystemModule
 
 ApplicationWindow {
     id: root
-    width: 500
-    height: 360
+    width: 650
+    height: 550
     flags: Qt.Window | Qt.FramelessWindowHint
     color: Colors.surface1
 
     menuBar: MyMenuBar {
         id: menuBar
-        implicitHeight: 20
-        rootWindow: root
+
+        dragWindow: root
+        implicitHeight: 27
         infoText: "About Qt"
     }
 
     Image {
         id: logo
+
         anchors.left: parent.left
         anchors.right: parent.right
         anchors.top: parent.top
         anchors.margins: 20
+
         source: "../icons/qt_logo.svg"
-        sourceSize: Qt.size(80, 80)
+        sourceSize.width: 80
+        sourceSize.height: 80
         fillMode: Image.PreserveAspectFit
+
         smooth: true
         antialiasing: true
         asynchronous: true
     }
 
-    TextArea {
-        anchors.top: logo.bottom
-        anchors.left: parent.left
-        anchors.right: parent.right
-        anchors.bottom: parent.bottom
-        anchors.margins: 20
-        antialiasing: true
-        wrapMode: Text.WrapAnywhere
-        color: Colors.textFile
-        horizontalAlignment: Text.AlignHCenter
-        readOnly: true
-        selectionColor: Colors.selection
-        text: qsTr("Qt Group (Nasdaq Helsinki: QTCOM) is a global software company with a strong \
-presence in more than 70 industries and is the leading independent technology behind 1+ billion \
-devices and applications. Qt is used by major global companies and developers worldwide, and the \
-technology enables its customers to deliver exceptional user experiences and advance their digital \
-transformation initiatives. Qt achieves this through its cross-platform software framework for the \
-development of apps and devices, under both commercial and open-source licenses.")
-        background: Rectangle {
-            color: "transparent"
-        }
+    ScrollView {
+      anchors.top: logo.bottom
+      anchors.left: parent.left
+      anchors.right: parent.right
+      anchors.bottom: parent.bottom
+      anchors.margins: 20
+
+      TextArea {
+          selectedTextColor: Colors.textFile
+          selectionColor: Colors.selection
+          horizontalAlignment: Text.AlignHCenter
+          textFormat: Text.RichText
+
+          text: qsTr("<h3>About Qt</h3>"
+                   + "<p>This program uses Qt version %1.</p>"
+                   + "<p>Qt is a C++ toolkit for cross-platform application "
+                   + "development.</p>"
+                   + "<p>Qt provides single-source portability across all major desktop "
+                   + "operating systems. It is also available for embedded Linux and other "
+                   + "embedded and mobile operating systems.</p>"
+                   + "<p>Qt is available under multiple licensing options designed "
+                   + "to accommodate the needs of our various users.</p>"
+                   + "<p>Qt licensed under our commercial license agreement is appropriate "
+                   + "for development of proprietary/commercial software where you do not "
+                   + "want to share any source code with third parties or otherwise cannot "
+                   + "comply with the terms of GNU (L)GPL.</p>"
+                   + "<p>Qt licensed under GNU (L)GPL is appropriate for the "
+                   + "development of Qt&nbsp;applications provided you can comply with the terms "
+                   + "and conditions of the respective licenses.</p>"
+                   + "<p>Please see <a href=\"http://%2/\">%2</a> "
+                   + "for an overview of Qt licensing.</p>"
+                   + "<p>Copyright (C) %3 The Qt Company Ltd and other "
+                   + "contributors.</p>"
+                   + "<p>Qt and the Qt logo are trademarks of The Qt Company Ltd.</p>"
+                   + "<p>Qt is The Qt Company Ltd product developed as an open source "
+                   + "project. See <a href=\"http://%4/\">%4</a> for more information.</p>")
+                   .arg(Application.version).arg("qt.io/licensing").arg("2023").arg("qt.io")
+          color: Colors.textFile
+          wrapMode: Text.WordWrap
+          readOnly: true
+          antialiasing: true
+          background: null
+
+          onLinkActivated: function(link) {
+              Qt.openUrlExternally(link)
+          }
+      }
+    }
+
+    ResizeButton {
+        resizeWindow: root
     }
-    ResizeButton {}
 }
index 280f8928643b07cce92eceedee1c1d3bf11cb937..285667773864c5a6e8dd8916c9d967a6b648c1ce 100644 (file)
@@ -1,22 +1,23 @@
 // Copyright (C) 2023 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
 
-pragma Singleton
 import QtQuick
 
+pragma Singleton
+
 QtObject {
-    readonly property color background: "#23272E"
-    readonly property color surface1: "#1E2227"
+    readonly property color background: "#292828"
+    readonly property color surface1: "#171819"
     readonly property color surface2: "#090A0C"
-    readonly property color text: "#ABB2BF"
-    readonly property color textFile: "#C5CAD3"
-    readonly property color disabledText: "#454D5F"
-    readonly property color selection: "#2C313A"
-    readonly property color active: "#23272E"
-    readonly property color inactive: "#3E4452"
-    readonly property color folder: "#3D4451"
-    readonly property color icon: "#3D4451"
-    readonly property color iconIndicator: "#E5C07B"
-    readonly property color color1: "#E06B74"
-    readonly property color color2: "#62AEEF"
+    readonly property color text: "#D4BE98"
+    readonly property color textFile: "#E1D2B7"
+    readonly property color disabledText: "#2C313A"
+    readonly property color selection: "#4B4A4A"
+    readonly property color active: "#292828"
+    readonly property color inactive: "#383737"
+    readonly property color folder: "#383737"
+    readonly property color icon: "#383737"
+    readonly property color iconIndicator: "#D5B35D"
+    readonly property color color1: "#A7B464"
+    readonly property color color2: "#D3869B"
 }
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Editor.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Editor.qml
new file mode 100644 (file)
index 0000000..80f7c04
--- /dev/null
@@ -0,0 +1,160 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import FileSystemModule
+
+pragma ComponentBehavior: Bound
+
+// This is the text editor that displays the currently open file, including
+// their corresponding line numbers.
+Rectangle {
+    id: root
+
+    required property string currentFilePath
+    required property bool showLineNumbers
+    property alias text: textArea
+    property int currentLineNumber: -1
+    property int rowHeight: Math.ceil(fontMetrics.lineSpacing)
+
+    color: Colors.background
+
+    onWidthChanged: textArea.update()
+    onHeightChanged: textArea.update()
+
+    RowLayout {
+        anchors.fill: parent
+        // We use a flickable to synchronize the position of the editor and
+        // the line numbers. This is necessary because the line numbers can
+        // extend the available height.
+        Flickable {
+            id: lineNumbers
+
+            // Calculate the width based on the logarithmic scale.
+            Layout.preferredWidth: fontMetrics.averageCharacterWidth
+                * (Math.floor(Math.log10(textArea.lineCount)) + 1) + 10
+            Layout.fillHeight: true
+
+            interactive: false
+            contentY: editorFlickable.contentY
+            visible: textArea.text !== "" && root.showLineNumbers
+
+            Column {
+                anchors.fill: parent
+                Repeater {
+                    id: repeatedLineNumbers
+
+                    model: LineNumberModel {
+                        lineCount: textArea.text !== "" ? textArea.lineCount : 0
+                    }
+
+                    delegate: Item {
+                        required property int index
+
+                        width: parent.width
+                        height: root.rowHeight
+                        Label {
+                            id: numbers
+
+                            text: parent.index + 1
+
+                            width: parent.width
+                            height: parent.height
+                            horizontalAlignment: Text.AlignLeft
+                            verticalAlignment: Text.AlignVCenter
+
+                            color: (root.currentLineNumber === parent.index)
+                                    ? Colors.iconIndicator : Qt.darker(Colors.text, 2)
+                            font: textArea.font
+                        }
+                        Rectangle {
+                            id: indicator
+
+                            anchors.left: numbers.right
+                            width: 1
+                            height: parent.height
+                            color: Qt.darker(Colors.text, 3)
+                        }
+                    }
+                }
+            }
+        }
+
+        Flickable {
+            id: editorFlickable
+
+            property alias textArea: textArea
+
+            // We use an inline component to customize the horizontal and vertical
+            // scroll-bars. This is convenient when the component is only used in one file.
+            component MyScrollBar: ScrollBar {
+                id: scrollBar
+                background: Rectangle {
+                    implicitWidth: scrollBar.interactive ? 8 : 4
+                    implicitHeight: scrollBar.interactive ? 8 : 4
+
+                    opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0
+                    color: Colors.background
+                    Behavior on opacity {
+                        OpacityAnimator {
+                            duration: 500
+                        }
+                    }
+                }
+                contentItem: Rectangle {
+                    implicitWidth: scrollBar.interactive ? 8 : 4
+                    implicitHeight: scrollBar.interactive ? 8 : 4
+                    opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0
+                    color: Colors.color1
+                    Behavior on opacity {
+                        OpacityAnimator {
+                            duration: 1000
+                        }
+                    }
+                }
+            }
+
+            Layout.fillHeight: true
+            Layout.fillWidth: true
+            ScrollBar.horizontal: MyScrollBar {}
+            ScrollBar.vertical: MyScrollBar {}
+
+            boundsBehavior: Flickable.StopAtBounds
+
+            TextArea.flickable: TextArea {
+                id: textArea
+                anchors.fill: parent
+
+                focus: false
+                topPadding: 0
+                leftPadding: 10
+
+                text: FileSystemModel.readFile(root.currentFilePath)
+                tabStopDistance: fontMetrics.averageCharacterWidth * 4
+
+                // Grab the current line number from the C++ interface.
+                onCursorPositionChanged: {
+                    root.currentLineNumber = FileSystemModel.currentLineNumber(
+                        textArea.textDocument, textArea.cursorPosition)
+                }
+
+                color: Colors.textFile
+                selectedTextColor: Colors.textFile
+                selectionColor: Colors.selection
+
+                textFormat: TextEdit.PlainText
+                renderType: Text.QtRendering
+                selectByMouse: true
+                antialiasing: true
+                background: null
+            }
+
+            FontMetrics {
+                id: fontMetrics
+                font: textArea.font
+            }
+        }
+    }
+}
index ade2e48c1f5d3fea7fbb3ac011c7b94ac2fea7c8..db955168c59dcde0fee507b134223f79bf209f2b 100644 (file)
@@ -2,26 +2,31 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
 
 import QtQuick
-import QtQuick.Layouts
+import QtQuick.Effects
 import QtQuick.Controls.Basic
 import FileSystemModule
 
+pragma ComponentBehavior: Bound
+
 // This is the file system view which gets populated by the C++ model.
 Rectangle {
     id: root
 
     signal fileClicked(string filePath)
+    property alias rootIndex: fileSystemTreeView.rootIndex
 
     TreeView {
         id: fileSystemTreeView
+
+        property int lastIndex: -1
+
         anchors.fill: parent
         model: FileSystemModel
+        rootIndex: FileSystemModel.rootIndex
         boundsBehavior: Flickable.StopAtBounds
         boundsMovement: Flickable.StopAtBounds
         clip: true
 
-        property int lastIndex: -1
-
         Component.onCompleted: fileSystemTreeView.toggleExpanded(0)
 
         // The delegate represents a single entry in the filesystem.
@@ -31,50 +36,101 @@ Rectangle {
             implicitWidth: fileSystemTreeView.width > 0 ? fileSystemTreeView.width : 250
             implicitHeight: 25
 
+            // Since we have the 'ComponentBehavior Bound' pragma, we need to
+            // require these properties from our model. This is a convenient way
+            // to bind the properties provided by the model's role names.
             required property int index
             required property url filePath
+            required property string fileName
 
-            indicator: null
-
-            contentItem: Item {
-                anchors.fill: parent
+            indicator: Image {
+                id: directoryIcon
 
-                Icon {
-                    id: directoryIcon
-                    x: leftMargin + (depth * indentation)
-                    anchors.verticalCenter: parent.verticalCenter
-                    path: treeDelegate.hasChildren
-                        ? (treeDelegate.expanded ? "../icons/folder_open.svg" : "../icons/folder_closed.svg")
+                x: treeDelegate.leftMargin + (treeDelegate.depth * treeDelegate.indentation)
+                anchors.verticalCenter: parent.verticalCenter
+                source: treeDelegate.hasChildren ? (treeDelegate.expanded
+                            ? "../icons/folder_open.svg" : "../icons/folder_closed.svg")
                         : "../icons/generic_file.svg"
-                    iconColor: (treeDelegate.expanded && treeDelegate.hasChildren) ? Colors.color2 : Colors.folder
-                }
-                Text {
-                    anchors.left: directoryIcon.right
-                    anchors.verticalCenter: parent.verticalCenter
-                    width: parent.width
-                    text: model.fileName
-                    color: Colors.text
-                }
+                sourceSize.width: 20
+                sourceSize.height: 20
+                fillMode: Image.PreserveAspectFit
+
+                smooth: true
+                antialiasing: true
+                asynchronous: true
+            }
+
+            contentItem: Text {
+                text: treeDelegate.fileName
+                color: Colors.text
             }
 
             background: Rectangle {
-                color: treeDelegate.index === fileSystemTreeView.lastIndex
+                color: (treeDelegate.index === fileSystemTreeView.lastIndex)
                     ? Colors.selection
                     : (hoverHandler.hovered ? Colors.active : "transparent")
             }
 
-            TapHandler {
-                onSingleTapped: {
-                    fileSystemTreeView.toggleExpanded(row)
-                    fileSystemTreeView.lastIndex = index
-                    // If this model item doesn't have children, it means it's representing a file.
-                    if (!treeDelegate.hasChildren)
-                        root.fileClicked(filePath)
+            // We color the directory icons with this MultiEffect, where we overlay
+            // the colorization color ontop of the SVG icons.
+            MultiEffect {
+                id: iconOverlay
+
+                anchors.fill: directoryIcon
+                source: directoryIcon
+                colorization: 1.0
+                brightness: 1.0
+                colorizationColor: {
+                    const isFile = treeDelegate.index === fileSystemTreeView.lastIndex
+                                    && !treeDelegate.hasChildren;
+                    if (isFile)
+                        return Qt.lighter(Colors.folder, 3)
+
+                    const isExpandedFolder = treeDelegate.expanded && treeDelegate.hasChildren;
+                    if (isExpandedFolder)
+                        return Colors.color2
+                    else
+                        return Colors.folder
                 }
             }
+
             HoverHandler {
                 id: hoverHandler
             }
+
+            TapHandler {
+                acceptedButtons: Qt.LeftButton | Qt.RightButton
+                onSingleTapped: (eventPoint, button) => {
+                    switch (button) {
+                        case Qt.LeftButton:
+                            fileSystemTreeView.toggleExpanded(treeDelegate.row)
+                            fileSystemTreeView.lastIndex = treeDelegate.index
+                            // If this model item doesn't have children, it means it's
+                            // representing a file.
+                            if (!treeDelegate.hasChildren)
+                                root.fileClicked(treeDelegate.filePath)
+                        break;
+                        case Qt.RightButton:
+                            if (treeDelegate.hasChildren)
+                                contextMenu.popup();
+                        break;
+                    }
+                }
+            }
+
+            MyMenu {
+                id: contextMenu
+                Action {
+                    text: qsTr("Set as root index")
+                    onTriggered: {
+                        fileSystemTreeView.rootIndex = fileSystemTreeView.index(treeDelegate.row, 0)
+                    }
+                }
+                Action {
+                    text: qsTr("Reset root index")
+                    onTriggered: fileSystemTreeView.rootIndex = undefined
+                }
+            }
         }
 
         // Provide our own custom ScrollIndicator for the TreeView.
@@ -85,6 +141,7 @@ Rectangle {
             contentItem: Rectangle {
                 implicitWidth: 6
                 implicitHeight: 6
+
                 color: Colors.color1
                 opacity: fileSystemTreeView.movingVertically ? 0.5 : 0.0
 
diff --git a/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Icon.qml b/examples/quickcontrols/filesystemexplorer/FileSystemModule/qml/Icon.qml
deleted file mode 100644 (file)
index 25162d9..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-import QtQuick
-import QtQuick.Effects
-
-// Custom Component for displaying Icons
-Item {
-    id: root
-
-    required property url path
-    property real padding: 5
-    property real size: 30
-    property alias iconColor: overlay.colorizationColor
-    property alias hovered: mouse.hovered
-
-    width: size
-    height: size
-
-    Image {
-        id: icon
-        anchors.fill: root
-        anchors.margins: padding
-        source: path
-        sourceSize: Qt.size(size, size)
-        fillMode: Image.PreserveAspectFit
-        smooth: true
-        antialiasing: true
-        asynchronous: true
-    }
-
-    MultiEffect {
-        id: overlay
-        anchors.fill: icon
-        source: icon
-        colorization: 1.0
-        brightness: 1.0
-    }
-
-    HoverHandler {
-        id: mouse
-        acceptedDevices: PointerDevice.Mouse
-    }
-}
index 99795b5e53f77f09213842c14e4e1c21feff8fd6..1f1d30c56697425b07b1ffbfda8e23e94bcd4ff5 100644 (file)
@@ -8,35 +8,38 @@ import FileSystemModule
 Menu {
     id: root
 
-    background: Rectangle {
-        implicitWidth: 200
-        implicitHeight: 40
-        color: Colors.surface2
-    }
-
     delegate: MenuItem {
         id: menuItem
-        implicitWidth: 200
-        implicitHeight: 40
         contentItem: Item {
             Text {
                 anchors.verticalCenter: parent.verticalCenter
                 anchors.left: parent.left
                 anchors.leftMargin: 5
+
                 text: menuItem.text
                 color: enabled ? Colors.text : Colors.disabledText
             }
             Rectangle {
+                id: indicator
+
                 anchors.verticalCenter: parent.verticalCenter
                 anchors.right: parent.right
                 width: 6
                 height: parent.height
+
                 visible: menuItem.highlighted
                 color: Colors.color2
             }
         }
         background: Rectangle {
+            implicitWidth: 210
+            implicitHeight: 35
             color: menuItem.highlighted ? Colors.active : "transparent"
         }
     }
+    background: Rectangle {
+        implicitWidth: 210
+        implicitHeight: 35
+        color: Colors.surface2
+    }
 }
index a2a3fea8861f85062a13fb82cc47feef260927a2..4874a2c03f270daa3a7bcda967736f6c2bfd6685 100644 (file)
@@ -6,130 +6,172 @@ import QtQuick.Layouts
 import QtQuick.Controls.Basic
 import FileSystemModule
 
-// The MenuBar also serves as a controller for our Window as we don't use any decorations.
+// The MenuBar also serves as a controller for our window as we don't use any decorations.
 MenuBar {
     id: root
 
-    required property ApplicationWindow rootWindow
+    required property ApplicationWindow dragWindow
     property alias infoText: windowInfo.text
 
-    implicitHeight: 25
-
-    // The top level menus on the left side
+    // Customization of the top level menus inside the MenuBar
     delegate: MenuBarItem {
         id: menuBarItem
-        implicitHeight: 25
 
         contentItem: Text {
             horizontalAlignment: Text.AlignLeft
             verticalAlignment: Text.AlignVCenter
-            color: menuBarItem.highlighted ? Colors.textFile : Colors.text
-            opacity: enabled ? 1.0 : 0.3
+
             text: menuBarItem.text
-            elide: Text.ElideRight
             font: menuBarItem.font
+            elide: Text.ElideRight
+            color: menuBarItem.highlighted ? Colors.textFile : Colors.text
+            opacity: enabled ? 1.0 : 0.3
         }
 
         background: Rectangle {
+            id: background
+
             color: menuBarItem.highlighted ? Colors.selection : "transparent"
             Rectangle {
                 id: indicator
+
                 width: 0; height: 3
                 anchors.horizontalCenter: parent.horizontalCenter
                 anchors.bottom: parent.bottom
-                color: Colors.color1
 
+                color: Colors.color1
                 states: State {
-                    name: "active"; when: menuBarItem.highlighted
-                    PropertyChanges { target: indicator; width: parent.width }
+                    name: "active"
+                    when: menuBarItem.highlighted
+                    PropertyChanges {
+                        indicator.width: background.width - 2
+                    }
                 }
-
                 transitions: Transition {
                     NumberAnimation {
                         properties: "width"
-                        duration: 300
+                        duration: 175
                     }
                 }
-
             }
         }
     }
+    // We use the contentItem property as a place to attach our window decorations. Beneath
+    // the usual menu entries within a MenuBar, it includes a centered information text, along
+    // with the minimize, maximize, and close buttons.
+    contentItem: RowLayout {
+        id: windowBar
 
-    // The background property contains an information text in the middle as well as the
-    // Minimize, Maximize and Close Buttons.
-    background: Rectangle {
-        color: Colors.surface2
-        // Make the empty space drag the specified root window.
-        WindowDragHandler { dragWindow: rootWindow }
+        Layout.fillWidth: true
+        Layout.fillHeight: true
+
+        spacing: root.spacing
+        Repeater {
+            id: menuBarItems
 
-        Text {
-            id: windowInfo
-            anchors.horizontalCenter: parent.horizontalCenter
-            anchors.verticalCenter: parent.verticalCenter
-            color: Colors.text
+            Layout.alignment: Qt.AlignLeft
+            model: root.contentModel
         }
 
-        component InteractionButton: Rectangle {
-            signal action;
-            property alias hovered: hoverHandler.hovered
+        Item {
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+            Text {
+                id: windowInfo
+
+                width: parent.width; height: parent.height
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+                leftPadding: windowActions.width
+                color: Colors.text
+                clip: true
+            }
+        }
 
-            width: root.height
-            anchors.top: parent.top
-            anchors.bottom: parent.bottom
-            color: hovered ? Colors.background : "transparent"
+        RowLayout {
+            id: windowActions
 
-            HoverHandler { id: hoverHandler }
-            TapHandler { onTapped: action() }
-        }
+            Layout.alignment: Qt.AlignRight
+            Layout.fillHeight: true
 
-        InteractionButton {
-            id: minimize
+            spacing: 0
 
-            anchors.right: maximize.left
-            onAction: rootWindow.showMinimized()
-            Rectangle {
-                width: parent.height - 10; height: 2
-                anchors.centerIn: parent
-                color: parent.hovered ? Colors.iconIndicator : Colors.icon
+            component InteractionButton: Rectangle {
+                id: interactionButton
+
+                signal action()
+                property alias hovered: hoverHandler.hovered
+
+                Layout.fillHeight: true
+                Layout.preferredWidth: height
+
+                color: hovered ? Colors.background : "transparent"
+                HoverHandler {
+                    id: hoverHandler
+                }
+                TapHandler {
+                    id: tapHandler
+                    onTapped: interactionButton.action()
+                }
             }
-        }
 
-        InteractionButton {
-            id: maximize
+            InteractionButton {
+                id: minimize
 
-            anchors.right: close.left
-            onAction: rootWindow.showMaximized()
-            Rectangle {
-                anchors.fill: parent
-                anchors.margins: 5
-                border.width: 2
-                color: "transparent"
-                border.color: parent.hovered ? Colors.iconIndicator : Colors.icon
+                onAction: root.dragWindow.showMinimized()
+                Rectangle {
+                    anchors.centerIn: parent
+                    color: parent.hovered ? Colors.iconIndicator : Colors.icon
+                    height: 2
+                    width: parent.height - 14
+                }
             }
-        }
 
-        InteractionButton {
-            id: close
+            InteractionButton {
+                id: maximize
 
-            color: hovered ? "#ec4143" : "transparent"
-            anchors.right: parent.right
-            onAction: rootWindow.close()
-            Rectangle {
-                width: parent.height - 8; height: 2
-                anchors.centerIn: parent
-                color: parent.hovered ? Colors.iconIndicator : Colors.icon
-                rotation: 45
-                transformOrigin: Item.Center
-                antialiasing: true
+                onAction: root.dragWindow.showMaximized()
+                Rectangle {
+                    anchors.fill: parent
+                    anchors.margins: 7
+                    border.color: parent.hovered ? Colors.iconIndicator : Colors.icon
+                    border.width: 2
+                    color: "transparent"
+                }
+            }
+
+            InteractionButton {
+                id: close
+
+                color: hovered ? "#ec4143" : "transparent"
+                onAction: root.dragWindow.close()
                 Rectangle {
-                    width: parent.height
-                    height: parent.width
                     anchors.centerIn: parent
-                    color: parent.color
+                    width: parent.height - 8; height: 2
+
+                    rotation: 45
                     antialiasing: true
+                    transformOrigin: Item.Center
+                    color: parent.hovered ? Colors.iconIndicator : Colors.icon
+
+                    Rectangle {
+                        anchors.centerIn: parent
+                        width: parent.height
+                        height: parent.width
+
+                        antialiasing: true
+                        color: parent.color
+                    }
                 }
             }
         }
     }
 
+    background: Rectangle {
+        color: Colors.surface2
+        // Make the empty space drag the specified root window.
+        WindowDragHandler {
+            dragWindow: root.dragWindow
+        }
+    }
 }
index eb2e5bc0276617c7f4c0623156edc6cac2b52ef6..0df65bf82f58f293499843980059d206d28b44d4 100644 (file)
@@ -5,6 +5,8 @@ import QtQuick.Controls
 import FileSystemModule
 
 Button {
+    required property ApplicationWindow resizeWindow
+
     icon.width: 20; icon.height: 20
     anchors.right: parent.right
     anchors.bottom: parent.bottom
@@ -12,12 +14,10 @@ Button {
     bottomPadding: 3
 
     icon.source: "../icons/resize.svg"
-    icon.color: down || checked ? Colors.iconIndicator : Colors.icon
+    icon.color: hovered ? Colors.iconIndicator : Colors.icon
 
+    background: null
     checkable: false
     display: AbstractButton.IconOnly
-    background: null
-    onPressed: {
-        root.startSystemResize(Qt.BottomEdge | Qt.RightEdge)
-    }
+    onPressed: resizeWindow.startSystemResize(Qt.BottomEdge | Qt.RightEdge)
 }
index 9d08562d9711c736fd997bd131d37aa89157f23e..aac53039426425e12ff921b1c2669fba9ba5659f 100644 (file)
@@ -8,77 +8,92 @@ import FileSystemModule
 
 Rectangle {
     id: root
+
+    property alias currentTabIndex: topBar.currentIndex
+    required property ApplicationWindow dragWindow
+    readonly property int tabBarSpacing: 10
+
     color: Colors.surface2
 
-    required property ApplicationWindow rootWindow
-    property alias currentTabIndex: tabBar.currentIndex
+    component SidebarEntry: Button {
+        id: sidebarButton
 
-    ColumnLayout {
-        anchors.fill: root
-        anchors.topMargin: 10
-        anchors.bottomMargin: 10
-        spacing: 10
+        Layout.alignment: Qt.AlignHCenter
+        Layout.fillWidth: true
 
-        // TabBar is designed to be horizontal, whereas we need a vertical bar.
-        // We can easily achieve that by using a Container.
-        Container {
-            id: tabBar
+        icon.color: down || checked ? Colors.iconIndicator : Colors.icon
+        icon.width: 27
+        icon.height: 27
 
-            Layout.fillWidth: true
+        topPadding: 0
+        rightPadding: 0
+        bottomPadding: 0
+        leftPadding: 0
+        background: null
 
-            // ButtonGroup ensures that only one button can be checked at a time.
-            ButtonGroup {
-                buttons: tabBar.contentItem.children
-                // We have to manage the currentIndex ourselves, which we do by setting it to the
-                // index of the currently checked button.
-                // We use setCurrentIndex instead of setting the currentIndex property to avoid breaking bindings.
-                // See "Managing the Current Index" in Container's documentation for more information.
-                onCheckedButtonChanged: tabBar.setCurrentIndex(Math.max(0, buttons.indexOf(checkedButton)))
-            }
+        Rectangle {
+            id: indicator
 
-            contentItem: ColumnLayout {
-                spacing: tabBar.spacing
+            anchors.verticalCenter: parent.verticalCenter
+            x: 2
+            width: 4
+            height: sidebarButton.icon.height * 1.2
 
-                Repeater {
-                    model: tabBar.contentModel
-                }
-            }
+            visible: sidebarButton.checked
+            color: Colors.color1
+        }
+    }
+
+    // TabBar is designed to be horizontal, whereas we need a vertical bar.
+    // We can easily achieve that by using a Container.
+    component TabBar: Container {
+        id: tabBarComponent
+
+        Layout.fillWidth: true
+        // ButtonGroup ensures that only one button can be checked at a time.
+        ButtonGroup {
+            buttons: tabBarComponent.contentChildren
+
+            // We have to manage the currentIndex ourselves, which we do by setting it to the index
+            // of the currently checked button. We use setCurrentIndex instead of setting the
+            // currentIndex property to avoid breaking bindings. See "Managing the Current Index"
+            // in Container's documentation for more information.
+            onCheckedButtonChanged: tabBarComponent.setCurrentIndex(
+                Math.max(0, buttons.indexOf(checkedButton)))
+        }
 
-            component SidebarEntry: Button {
-                id: sidebarButton
-                icon.color: down || checked ? Colors.iconIndicator : Colors.icon
-                icon.width: 35
-                icon.height: 35
-                leftPadding: 8 + indicator.width
-
-                background: null
-
-                Rectangle {
-                    id: indicator
-                    x: 4
-                    anchors.verticalCenter: parent.verticalCenter
-                    width: 4
-                    height: sidebarButton.icon.width
-                    color: Colors.color1
-                    visible: sidebarButton.checked
-                }
+        contentItem: ColumnLayout {
+            spacing: tabBarComponent.spacing
+            Repeater {
+                model: tabBarComponent.contentModel
             }
+        }
+    }
 
+    ColumnLayout {
+        anchors.fill: root
+        anchors.topMargin: root.tabBarSpacing
+        anchors.bottomMargin: root.tabBarSpacing
+
+        spacing: root.tabBarSpacing
+        TabBar {
+            id: topBar
+
+            spacing: root.tabBarSpacing
             // Shows help text when clicked.
             SidebarEntry {
+                id: infoTab
                 icon.source: "../icons/light_bulb.svg"
                 checkable: true
                 checked: true
-
-                Layout.alignment: Qt.AlignHCenter
             }
 
             // Shows the file system when clicked.
             SidebarEntry {
+                id: filesystemTab
+
                 icon.source: "../icons/read.svg"
                 checkable: true
-
-                Layout.alignment: Qt.AlignHCenter
             }
         }
 
@@ -88,25 +103,31 @@ Rectangle {
             Layout.fillWidth: true
 
             // Make the empty space drag our main window.
-            WindowDragHandler { dragWindow: rootWindow }
+            WindowDragHandler {
+                dragWindow: root.dragWindow
+            }
         }
 
-        // Opens the Qt website in the system's web browser.
-        SidebarEntry {
-            id: qtWebsiteButton
-            icon.source: "../icons/globe.svg"
-            checkable: false
+        TabBar {
+            id: bottomBar
 
-            onClicked: Qt.openUrlExternally("https://www.qt.io/")
-        }
+            spacing: root.tabBarSpacing
+            // Opens the Qt website in the system's web browser.
+            SidebarEntry {
+                id: qtWebsiteButton
+                icon.source: "../icons/globe.svg"
+                checkable: false
+                onClicked: Qt.openUrlExternally("https://www.qt.io/")
+            }
 
-        // Opens the About Qt Window.
-        SidebarEntry {
-            id: aboutQtButton
-            icon.source: "../icons/info_sign.svg"
-            checkable: false
+            // Opens the About Qt Window.
+            SidebarEntry {
+                id: aboutQtButton
 
-            onClicked: aboutQtWindow.visible = !aboutQtWindow.visible
+                icon.source: "../icons/info_sign.svg"
+                checkable: false
+                onClicked: aboutQtWindow.visible = !aboutQtWindow.visible
+            }
         }
     }
 
index ff7ecb757ce1b5c1ee0a69243af266117f420f7b..b1f684600d34136b008f64fbb57220ad89193dc1 100644 (file)
@@ -1,7 +1,7 @@
 module FileSystemModule
 Main 1.0 Main.qml
-Icon 1.0 qml/Icon.qml
 About 1.0 qml/About.qml
+Editor 1.0 qml/Editor.qml
 MyMenu 1.0 qml/MyMenu.qml
 Sidebar 1.0 qml/Sidebar.qml
 MyMenuBar 1.0 qml/MyMenuBar.qml
index 0260928b6c4be619210ac0196e9c69ce1a775a3e..b46cbec7918440325dfd97f1409781c901d557d9 100644 (file)
@@ -37,3 +37,16 @@ pleasing UIs.
 .. image:: filesystemexplorer.webp
    :target: filesystemexplorer.webp
    :alt: QtQuickControls Filesystem Explorer Screenshot
+
+References
+----------
+
+If you're interested in the C++ version of this example, you can find it
+`here <https://doc-snapshots.qt.io/qt6-dev/qtquickcontrols-filesystemexplorer-example.html>`_.
+
+Additionally, there is a detailed
+`tutorial <https://doc.qt.io/qtforpython-6/tutorials/extendedexplorer/extendedexplorer.html>`_
+available that provides step-by-step instructions on how to extend this example
+with additional features. This tutorial can be helpful if you want to explore
+and learn more about building upon the existing functionality of the filesystem
+explorer.
index cce7e1daf0617d95cfc5329df147d740d90b0557..10ad0d26e718277f4f0958af5ec059a3aa142b04 100644 (file)
Binary files a/examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.webp and b/examples/quickcontrols/filesystemexplorer/doc/filesystemexplorer.webp differ
diff --git a/examples/quickcontrols/filesystemexplorer/editormodels.py b/examples/quickcontrols/filesystemexplorer/editormodels.py
new file mode 100644 (file)
index 0000000..6881477
--- /dev/null
@@ -0,0 +1,116 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtWidgets import QFileSystemModel
+from PySide6.QtQuick import QQuickTextDocument
+from PySide6.QtQml import QmlElement, QmlSingleton
+from PySide6.QtCore import (Qt, QDir, QAbstractListModel, Slot, QFile, QTextStream,
+                            QMimeDatabase, QFileInfo, QStandardPaths, QModelIndex,
+                            Signal, Property)
+
+QML_IMPORT_NAME = "FileSystemModule"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+@QmlSingleton
+class FileSystemModel(QFileSystemModel):
+
+    rootIndexChanged = Signal()
+
+    def getDefaultRootDir():
+        return QStandardPaths.writableLocation(QStandardPaths.StandardLocation.HomeLocation)
+
+    def __init__(self, parent=None):
+        super().__init__(parent=parent)
+        self.mRootIndex = QModelIndex()
+        self.mDb = QMimeDatabase()
+        self.setFilter(QDir.Filter.AllEntries | QDir.Filter.Hidden | QDir.Filter.NoDotAndDotDot)
+        self.setInitialDirectory()
+
+    # check for the correct mime type and then read the file.
+    # returns the text file's content or an error message on failure
+    @Slot(str, result=str)
+    def readFile(self, path):
+        if path == "":
+            return ""
+
+        file = QFile(path)
+
+        mime = self.mDb.mimeTypeForFile(QFileInfo(file))
+        if ('text' in mime.comment().lower()
+                or any('text' in s.lower() for s in mime.parentMimeTypes())):
+            if file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text):
+                stream = QTextStream(file).readAll()
+                file.close()
+                return stream
+            else:
+                return self.tr("Error opening the file!")
+        return self.tr("File type not supported!")
+
+    @Slot(QQuickTextDocument, int, result=int)
+    def currentLineNumber(self, textDocument, cursorPosition):
+        td = textDocument.textDocument()
+        tb = td.findBlock(cursorPosition)
+        return tb.blockNumber()
+
+    def setInitialDirectory(self, path=getDefaultRootDir()):
+        dir = QDir(path)
+        if dir.makeAbsolute():
+            self.setRootPath(dir.path())
+        else:
+            self.setRootPath(self.getDefaultRootDir())
+        self.setRootIndex(self.index(dir.path()))
+
+    # we only need one column in this example
+    def columnCount(self, parent):
+        return 1
+
+    @Property(QModelIndex, notify=rootIndexChanged)
+    def rootIndex(self):
+        return self.mRootIndex
+
+    def setRootIndex(self, index):
+        if (index == self.mRootIndex):
+            return
+        self.mRootIndex = index
+        self.rootIndexChanged.emit()
+
+
+@QmlElement
+class LineNumberModel(QAbstractListModel):
+
+    lineCountChanged = Signal()
+
+    def __init__(self, parent=None):
+        self.mLineCount = 0
+        super().__init__(parent=parent)
+
+    @Property(int, notify=lineCountChanged)
+    def lineCount(self):
+        return self.mLineCount
+
+    @lineCount.setter
+    def lineCount(self, n):
+        if n < 0:
+            print("lineCount must be greater then zero")
+            return
+        if self.mLineCount == n:
+            return
+
+        if self.mLineCount < n:
+            self.beginInsertRows(QModelIndex(), self.mLineCount, n - 1)
+            self.mLineCount = n
+            self.endInsertRows()
+        else:
+            self.beginRemoveRows(QModelIndex(), n, self.mLineCount - 1)
+            self.mLineCount = n
+            self.endRemoveRows()
+
+    def rowCount(self, parent):
+        return self.mLineCount
+
+    def data(self, index, role):
+        if not self.checkIndex(index) or role != Qt.ItemDataRole.DisplayRole:
+            return
+        return index.row()
diff --git a/examples/quickcontrols/filesystemexplorer/filesystemexplorer.py b/examples/quickcontrols/filesystemexplorer/filesystemexplorer.py
deleted file mode 100644 (file)
index 2bc733c..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-"""
-This example shows how to customize Qt Quick Controls by implementing a simple filesystem explorer.
-"""
-
-# Compile both resource files app.qrc and icons.qrc and include them here if you wish
-# to load them from the resource system. Currently, all resources are loaded locally
-# import FileSystemModule.rc_icons
-# import FileSystemModule.rc_app
-
-from PySide6.QtWidgets import QFileSystemModel
-from PySide6.QtGui import QGuiApplication
-from PySide6.QtQml import (QQmlApplicationEngine, QmlElement, QmlSingleton)
-from PySide6.QtCore import (Slot, QFile, QTextStream, QMimeDatabase, QFileInfo, QStandardPaths)
-
-import sys
-
-
-QML_IMPORT_NAME = "FileSystemModule"
-QML_IMPORT_MAJOR_VERSION = 1
-
-
-@QmlElement
-@QmlSingleton
-class FileSystemModel(QFileSystemModel):
-    def __init__(self, parent=None):
-        super().__init__(parent=parent)
-        self.setRootPath(QStandardPaths.writableLocation(QStandardPaths.HomeLocation))
-        self.db = QMimeDatabase()
-
-    # we only need one column in this example
-    def columnCount(self, parent):
-        return 1
-
-    # check for the correct mime type and then read the file.
-    # returns the text file's content or an error message on failure
-    @Slot(str, result=str)
-    def readFile(self, path):
-        if path == "":
-            return ""
-
-        file = QFile(path)
-
-        mime = self.db.mimeTypeForFile(QFileInfo(file))
-        if ('text' in mime.comment().lower()
-                or any('text' in s.lower() for s in mime.parentMimeTypes())):
-            if file.open(QFile.ReadOnly | QFile.Text):
-                stream = QTextStream(file).readAll()
-                return stream
-            else:
-                return self.tr("Error opening the file!")
-        return self.tr("File type not supported!")
-
-
-if __name__ == '__main__':
-    app = QGuiApplication(sys.argv)
-    app.setOrganizationName("QtProject")
-    app.setApplicationName("File System Explorer")
-    engine = QQmlApplicationEngine()
-    # Include the path of this file to search for the 'qmldir' module
-    engine.addImportPath(sys.path[0])
-
-    engine.loadFromModule("FileSystemModule", "Main")
-
-    if not engine.rootObjects():
-        sys.exit(-1)
-
-    sys.exit(app.exec())
index 1e1aa2ad86eb851e12997e09d30e10bb2a1816ea..8053cfab05ccf1f655ecae79da94678196ad003c 100644 (file)
@@ -1,19 +1,21 @@
 {
  "files": [
-    "filesystemexplorer.py",
+    "main.py",
+    "editormodels.py",
     "FileSystemModule/qmldir",
     "FileSystemModule/app.qrc",
     "FileSystemModule/qmldir",
     "FileSystemModule/Main.qml",
     "FileSystemModule/qml/About.qml",
     "FileSystemModule/qml/Colors.qml",
+    "FileSystemModule/qml/Editor.qml",
     "FileSystemModule/qml/FileSystemView.qml",
-    "FileSystemModule/qml/Icon.qml",
     "FileSystemModule/qml/MyMenu.qml",
     "FileSystemModule/qml/MyMenuBar.qml",
     "FileSystemModule/qml/ResizeButton.qml",
     "FileSystemModule/qml/Sidebar.qml",
     "FileSystemModule/qml/WindowDragHandler.qml",
+    "FileSystemModule/icons/app_icon.svg",
     "FileSystemModule/icons/folder_closed.svg",
     "FileSystemModule/icons/folder_open.svg",
     "FileSystemModule/icons/generic_file.svg",
diff --git a/examples/quickcontrols/filesystemexplorer/main.py b/examples/quickcontrols/filesystemexplorer/main.py
new file mode 100644 (file)
index 0000000..8fad951
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+"""
+This example shows how to customize Qt Quick Controls by implementing a simple filesystem explorer.
+"""
+
+# Compile both resource files app.qrc and icons.qrc and include them here if you wish
+# to load them from the resource system. Currently, all resources are loaded locally
+# import FileSystemModule.rc_icons
+# import FileSystemModule.rc_app
+
+from editormodels import FileSystemModel  # noqa: F401
+from PySide6.QtGui import QGuiApplication, QIcon
+from PySide6.QtQml import QQmlApplicationEngine
+from PySide6.QtCore import QCommandLineParser, qVersion
+
+import sys
+
+if __name__ == '__main__':
+    app = QGuiApplication(sys.argv)
+    app.setOrganizationName("QtProject")
+    app.setApplicationName("File System Explorer")
+    app.setApplicationVersion(qVersion())
+    app.setWindowIcon(QIcon(sys.path[0] + "/FileSystemModule/icons/app_icon.svg"))
+
+    parser = QCommandLineParser()
+    parser.setApplicationDescription("Qt Filesystemexplorer Example")
+    parser.addHelpOption()
+    parser.addVersionOption()
+    parser.addPositionalArgument("", "Initial directory", "[path]")
+    parser.process(app)
+    args = parser.positionalArguments()
+
+    engine = QQmlApplicationEngine()
+    # Include the path of this file to search for the 'qmldir' module
+    engine.addImportPath(sys.path[0])
+
+    engine.loadFromModule("FileSystemModule", "Main")
+
+    if not engine.rootObjects():
+        sys.exit(-1)
+
+    if (len(args) == 1):
+        fsm = engine.singletonInstance("FileSystemModule", "FileSystemModel")
+        fsm.setInitialDirectory(args[0])
+
+    sys.exit(app.exec())
index e96e99df4c2434e0d6e09cfdac4b8813763dc8b1..51b6b4c20297397fd4f3a0363dd3214381866819 100644 (file)
@@ -165,23 +165,27 @@ Using CMake
 You can build and run this example by executing the following commands
 (slightly adapted to your file system layout) in a terminal:
 
-macOS/Linux:
+Run CMake on macOS/Linux:
 
 .. code-block:: bash
 
     cd ~/pyside-setup/examples/samplebinding
+    mkdir build
+    cd build
+    cmake .. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release
 
-On Windows:
+Run CMake on Windows:
 
 .. code-block:: bash
 
     cd C:\pyside-setup\examples\samplebinding
-
-.. code-block:: bash
-
     mkdir build
     cd build
-    cmake -H.. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release
+    cmake .. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=cl.exe
+
+To build:
+
+.. code-block:: bash
     ninja
     ninja install
     cd ..
@@ -220,13 +224,13 @@ passing the compiler on the command line:
 
 .. code-block:: bash
 
-    cmake -H.. -B. -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe
+    cmake -S.. -B. -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe
 
 or by using the -G option:
 
 .. code-block:: bash
 
-    cmake -H.. -B. -G "Visual Studio 14 Win64"
+    cmake -S.. -B. -G "Visual Studio 14 Win64"
 
 If the ``-G "Visual Studio 14 Win64"`` option is used, a ``sln`` file
 will be generated, and can be used with ``MSBuild``
index b00d65415078e76395f0581b3f3ba4eca638450f..bbabb1247b2a9f923d9e6c10e5f44bcc26b88912 100644 (file)
@@ -72,21 +72,22 @@ macOS/Linux:
 .. code-block:: bash
 
     cd ~/pyside-setup/examples/scriptableapplication
+    mkdir build
+    cd build
+    cmake .. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release
+    ninja
+    ./scriptableapplication
 
 On Windows:
 
 .. code-block:: bash
 
     cd C:\pyside-setup\examples\scriptableapplication
-
-
-.. code-block:: bash
-
     mkdir build
     cd build
-    cmake -H.. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release
+    cmake .. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=cl.exe
     ninja
-    ./scriptableapplication
+    .\scriptableapplication.exe
 
 Using QMake
 +++++++++++
@@ -127,13 +128,13 @@ passing the compiler on the command line:
 
 .. code-block:: bash
 
-    cmake -H.. -B. -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe
+    cmake -S.. -B. -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe
 
 or using the -G option:
 
 .. code-block:: bash
 
-    cmake -H.. -B. -G "Visual Studio 14 Win64" -DCMAKE_BUILD_TYPE=Release
+    cmake -S.. -B. -G "Visual Studio 14 Win64" -DCMAKE_BUILD_TYPE=Release
 
 
 If the ``-G "Visual Studio 14 Win64"`` option is used, a ``sln`` file
index 26d80a7de36dd3a606cf7410366263a4d91e8419..ece7989e772ad83d859f86a80b0664906ffc3057 100644 (file)
@@ -41,18 +41,18 @@ MainWindow::MainWindow()
     diagnosticAction->setShortcut(Qt::CTRL | Qt::Key_D);
     fileMenu->addAction(tr("&Invoke testFunction1()"),
                         this, &MainWindow::testFunction1);
-    const QIcon quitIcon = QIcon::fromTheme("application-exit"_L1);
+    const QIcon quitIcon = QIcon::fromTheme(QIcon::ThemeIcon::ApplicationExit);
     auto *quitAction = fileMenu->addAction(quitIcon, tr("&Quit"),
                                            qApp, &QCoreApplication::quit);
     quitAction->setShortcut(Qt::CTRL | Qt::Key_Q);
 
     auto *editMenu = menuBar()->addMenu(tr("&Edit"));
-    const QIcon clearIcon = QIcon::fromTheme("edit-clear"_L1);
+    const QIcon clearIcon = QIcon::fromTheme(QIcon::ThemeIcon::EditClear);
     auto *clearAction = editMenu->addAction(clearIcon, tr("&Clear"),
                                             m_scriptEdit, &QPlainTextEdit::clear);
 
     auto *helpMenu = menuBar()->addMenu(tr("&Help"));
-    const QIcon aboutIcon = QIcon::fromTheme("help-about"_L1);
+    const QIcon aboutIcon = QIcon::fromTheme(QIcon::ThemeIcon::HelpAbout);
     auto *aboutAction = helpMenu->addAction(aboutIcon, tr("&About Qt"),
                                             qApp, &QApplication::aboutQt);
 
index 476243f9b613a2441de5e177cb41dea2fb69c2ef..e72f5ca72d9e74ca7aa6eede795d918ec9eb4214 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <QtWidgets/QMainWindow>
 
-class QPlainTextEdit;
+QT_FORWARD_DECLARE_CLASS(QPlainTextEdit)
 
 class MainWindow : public QMainWindow
 {
@@ -16,6 +16,8 @@ public:
 
     void testFunction1();
 
+    static constexpr auto TEST = QLatin1StringView("test");
+
 private Q_SLOTS:
     void slotRunScript();
     void slotPrintDiagnostics();
index 7f05cdedb3428e8ab3bc916fa132272aa3232a8a..09e959159b4993cdbda5ee9e3854d88988b433df 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <QtCore/QStringList>
 
-class QObject;
+QT_FORWARD_DECLARE_CLASS(QObject)
 
 namespace PythonUtils {
 
index 250e653bea83f11b143abd333fa1ec13d53c59de..d2f0e74a58303e243ca17e01cde218a3ed61582c 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'canbusdeviceinfobox.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.1
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
index fd391a2a801de16299e95104738cfa85ba5cef77..c32e9ca2d62511d7b13840191085507488737d08 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'canbusdeviceinfodialog.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.1
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -35,7 +35,7 @@ class Ui_CanBusDeviceInfoDialog(object):
 
         self.horizontalLayout = QHBoxLayout()
         self.horizontalLayout.setObjectName(u"horizontalLayout")
-        self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+        self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
 
         self.horizontalLayout.addItem(self.horizontalSpacer)
 
index 815fcf5940e6b2ef48356f19f299965ea6f59f46..f01adc4ebebcd1c88166ea95a12f15f559421247 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'connectdialog.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.1
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -169,7 +169,7 @@ class Ui_ConnectDialog(object):
 
         self.horizontalLayout = QHBoxLayout()
         self.horizontalLayout.setObjectName(u"horizontalLayout")
-        self.horizontalSpacer = QSpacerItem(96, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+        self.horizontalSpacer = QSpacerItem(96, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
 
         self.horizontalLayout.addItem(self.horizontalSpacer)
 
index cce2375cf730b2271eb39571ac64206138bf0661..4ba4dd309483899eda0141973ced22bce05118b4 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'mainwindow.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.1
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -95,7 +95,7 @@ class Ui_MainWindow(object):
 
         self.horizontalLayout.addWidget(self.busStatus)
 
-        self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+        self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
 
         self.horizontalLayout.addItem(self.horizontalSpacer)
 
@@ -119,7 +119,7 @@ class Ui_MainWindow(object):
         MainWindow.setMenuBar(self.menuBar)
         self.mainToolBar = QToolBar(MainWindow)
         self.mainToolBar.setObjectName(u"mainToolBar")
-        MainWindow.addToolBar(Qt.TopToolBarArea, self.mainToolBar)
+        MainWindow.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.mainToolBar)
         self.statusBar = QStatusBar(MainWindow)
         self.statusBar.setObjectName(u"statusBar")
         MainWindow.setStatusBar(self.statusBar)
index b769645e0c8f36a824f55a535d7d1a39a4253d8c..79f013c89ef7f9258a92f4f1be9e0ca74fd50c63 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'sendframebox.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.1
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -88,7 +88,7 @@ class Ui_SendFrameBox(object):
 
         self.frameIdEdit = QLineEdit(SendFrameBox)
         self.frameIdEdit.setObjectName(u"frameIdEdit")
-        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(1)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.frameIdEdit.sizePolicy().hasHeightForWidth())
@@ -109,7 +109,7 @@ class Ui_SendFrameBox(object):
 
         self.payloadEdit = QLineEdit(SendFrameBox)
         self.payloadEdit.setObjectName(u"payloadEdit")
-        sizePolicy1 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
+        sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
         sizePolicy1.setHorizontalStretch(2)
         sizePolicy1.setVerticalStretch(0)
         sizePolicy1.setHeightForWidth(self.payloadEdit.sizePolicy().hasHeightForWidth())
index 10fb0874f1dc9a09745ba6f621c548ab069024b8..1535fc8d8570937f351898947c798321363d0d30 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'mainwindow.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.1
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -61,7 +61,7 @@ class Ui_MainWindow(object):
         self.gridLayout.setObjectName(u"gridLayout")
         self.label_27 = QLabel(self.centralWidget)
         self.label_27.setObjectName(u"label_27")
-        sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.label_27.sizePolicy().hasHeightForWidth())
@@ -71,7 +71,7 @@ class Ui_MainWindow(object):
 
         self.connectButton = QPushButton(self.centralWidget)
         self.connectButton.setObjectName(u"connectButton")
-        sizePolicy1 = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
+        sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Fixed)
         sizePolicy1.setHorizontalStretch(0)
         sizePolicy1.setVerticalStretch(0)
         sizePolicy1.setHeightForWidth(self.connectButton.sizePolicy().hasHeightForWidth())
@@ -81,7 +81,7 @@ class Ui_MainWindow(object):
 
         self.gridLayout.addWidget(self.connectButton, 0, 7, 1, 1)
 
-        self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+        self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
 
         self.gridLayout.addItem(self.horizontalSpacer, 0, 4, 1, 1)
 
@@ -115,7 +115,7 @@ class Ui_MainWindow(object):
 
         self.portEdit = QLineEdit(self.centralWidget)
         self.portEdit.setObjectName(u"portEdit")
-        sizePolicy2 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
+        sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
         sizePolicy2.setHorizontalStretch(0)
         sizePolicy2.setVerticalStretch(0)
         sizePolicy2.setHeightForWidth(self.portEdit.sizePolicy().hasHeightForWidth())
@@ -255,7 +255,7 @@ class Ui_MainWindow(object):
 
         self.horizontalLayout.addWidget(self.writeTable)
 
-        self.horizontalSpacer_2 = QSpacerItem(13, 17, QSizePolicy.Expanding, QSizePolicy.Minimum)
+        self.horizontalSpacer_2 = QSpacerItem(13, 17, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
 
         self.horizontalLayout.addItem(self.horizontalSpacer_2)
 
index f1c29959416bbbf0c1267a42b8fd37615f9d6224..af3a0665c7e9257be44f573dec82211d9816cdd1 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'settingsdialog.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.1
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -26,7 +26,7 @@ class Ui_SettingsDialog(object):
         SettingsDialog.resize(239, 256)
         self.gridLayout = QGridLayout(SettingsDialog)
         self.gridLayout.setObjectName(u"gridLayout")
-        self.verticalSpacer = QSpacerItem(20, 43, QSizePolicy.Minimum, QSizePolicy.Expanding)
+        self.verticalSpacer = QSpacerItem(20, 43, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
 
         self.gridLayout.addItem(self.verticalSpacer, 3, 1, 1, 1)
 
index 6aa0fcc53665cf9bede1dc5024d69d8feddb8bea..21adbd5c12274e281f098c12b7c75508df92958f 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'mainwindow.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -74,7 +74,7 @@ class Ui_MainWindow(object):
         MainWindow.setMenuBar(self.menuBar)
         self.mainToolBar = QToolBar(MainWindow)
         self.mainToolBar.setObjectName(u"mainToolBar")
-        MainWindow.addToolBar(Qt.TopToolBarArea, self.mainToolBar)
+        MainWindow.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.mainToolBar)
         self.statusBar = QStatusBar(MainWindow)
         self.statusBar.setObjectName(u"statusBar")
         MainWindow.setStatusBar(self.statusBar)
index 212b60b25a8b7127bdad46659e353f8732099709..6c5a417cc64d2f2923a14c2bc07f8e31e9d81252 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'settingsdialog.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -128,7 +128,7 @@ class Ui_SettingsDialog(object):
 
         self.horizontalLayout = QHBoxLayout()
         self.horizontalLayout.setObjectName(u"horizontalLayout")
-        self.horizontalSpacer = QSpacerItem(96, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+        self.horizontalSpacer = QSpacerItem(96, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
 
         self.horizontalLayout.addItem(self.horizontalSpacer)
 
index b42d35f03f9372a83a5d1c54101b445050999deb..ab132e7fb2bb5eb25912ee2632385ff09acf532d 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'mainwindow.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -31,7 +31,7 @@ class Ui_MainWindow(object):
         self.verticalLayout.setObjectName(u"verticalLayout")
         self.plainTextEdit = QPlainTextEdit(self.centralwidget)
         self.plainTextEdit.setObjectName(u"plainTextEdit")
-        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.plainTextEdit.sizePolicy().hasHeightForWidth())
@@ -43,7 +43,7 @@ class Ui_MainWindow(object):
         self.gridLayout.setObjectName(u"gridLayout")
         self.label_5 = QLabel(self.centralwidget)
         self.label_5.setObjectName(u"label_5")
-        sizePolicy1 = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
+        sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
         sizePolicy1.setHorizontalStretch(0)
         sizePolicy1.setVerticalStretch(0)
         sizePolicy1.setHeightForWidth(self.label_5.sizePolicy().hasHeightForWidth())
@@ -95,7 +95,7 @@ class Ui_MainWindow(object):
 
         self.language = QComboBox(self.centralwidget)
         self.language.setObjectName(u"language")
-        sizePolicy2 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
+        sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
         sizePolicy2.setHorizontalStretch(0)
         sizePolicy2.setVerticalStretch(0)
         sizePolicy2.setHeightForWidth(self.language.sizePolicy().hasHeightForWidth())
@@ -169,7 +169,7 @@ class Ui_MainWindow(object):
 
         self.verticalLayout.addLayout(self.horizontalLayout)
 
-        self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
+        self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
 
         self.verticalLayout.addItem(self.verticalSpacer)
 
index 17589157726b433337a40970fc81abbe357e3f57..52795217e285ac92b3081023f5cad63c685996cd 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'bookwindow.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.2.3
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
index e8333e2f9b3460ad7e653cc3c2410e7074debebc..d3067eec14c4f9fcf6a366d1cf477d1cf93a0ae5 100644 (file)
@@ -196,7 +196,7 @@ def find_package_path(dir_name):
     return None
 
 
-# Return version as "3.7"
+# Return version as "x.y" (e.g. 3.9, 3.12, etc)
 def python_version():
     return str(sys.version_info[0]) + '.' + str(sys.version_info[1])
 
index 866d2a2e4efa3420a2bec85dc0feed7a08e0a1cb..36c2fe400a057cf05188177b8c84c07969cf7735 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'dialog.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.2.3
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
index 0705ebfda42b562614c37b26be79600b6a3c0c73..0be7691192c44821998122e7bcf17d02336a142c 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'mainwindow.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.2.3
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
index 4efdfbdd4290f415f44c53ec92310d01f5a3b069..43b8112004eef19347fc0af20e2b3060f0d4df23 100644 (file)
@@ -45,8 +45,10 @@ class BrowserWindow(QMainWindow):
         self._profile = profile
         self._tab_widget = TabWidget(profile, self)
 
-        self._stop_icon = QIcon(":process-stop.png")
-        self._reload_icon = QIcon(":view-refresh.png")
+        self._stop_icon = QIcon.fromTheme(QIcon.ThemeIcon.ProcessStop,
+                                          QIcon(":process-stop.png"))
+        self._reload_icon = QIcon.fromTheme(QIcon.ThemeIcon.ViewRefresh,
+                                            QIcon(":view-refresh.png"))
 
         self.setAttribute(Qt.WA_DeleteOnClose, True)
         self.setFocusPolicy(Qt.ClickFocus)
@@ -357,7 +359,9 @@ class BrowserWindow(QMainWindow):
         back_shortcuts.append(QKeySequence(Qt.Key_Back))
         self._history_back_action.setShortcuts(back_shortcuts)
         self._history_back_action.setIconVisibleInMenu(False)
-        self._history_back_action.setIcon(QIcon(":go-previous.png"))
+        back_icon = QIcon.fromTheme(QIcon.ThemeIcon.GoPrevious,
+                                    QIcon(":go-previous.png"))
+        self._history_back_action.setIcon(back_icon)
         self._history_back_action.setToolTip("Go back in history")
         self._history_back_action.triggered.connect(self._back)
         navigation_bar.addAction(self._history_back_action)
@@ -367,7 +371,9 @@ class BrowserWindow(QMainWindow):
         fwd_shortcuts.append(QKeySequence(Qt.Key_Forward))
         self._history_forward_action.setShortcuts(fwd_shortcuts)
         self._history_forward_action.setIconVisibleInMenu(False)
-        self._history_forward_action.setIcon(QIcon(":go-next.png"))
+        next_icon = QIcon.fromTheme(QIcon.ThemeIcon.GoNext,
+                                    QIcon(":go-next.png"))
+        self._history_forward_action.setIcon(next_icon)
         self._history_forward_action.setToolTip("Go forward in history")
         self._history_forward_action.triggered.connect(self._forward)
         navigation_bar.addAction(self._history_forward_action)
index 6f3dbf78f52c0bc7673c4dba97be4930599e899f..3b4973cb810deabb1a33e111a706e10a76d004a8 100644 (file)
@@ -34,8 +34,10 @@ class DownloadWidget(QFrame):
         self._download = download
         self._time_added = QElapsedTimer()
         self._time_added.start()
-        self._cancel_icon = QIcon(":process-stop.png")
-        self._remove_icon = QIcon(":edit-clear.png")
+        self._cancel_icon = QIcon.fromTheme(QIcon.ThemeIcon.ProcessStop,
+                                            QIcon(":process-stop.png"))
+        self._remove_icon = QIcon.fromTheme(QIcon.ThemeIcon.EditClear,
+                                            QIcon(":edit-clear.png"))
 
         self._ui = Ui_DownloadWidget()
         self._ui.setupUi(self)
index bf2fef36a0fdad4e1ab216ca0bd7fdbb751a7658..a963f0ac0dba7a3c8cad3d80f38431df0243aef6 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'certificateerrordialog.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -35,7 +35,7 @@ class Ui_CertificateErrorDialog(object):
 
         self.m_errorLabel = QLabel(CertificateErrorDialog)
         self.m_errorLabel.setObjectName(u"m_errorLabel")
-        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.m_errorLabel.sizePolicy().hasHeightForWidth())
@@ -47,7 +47,7 @@ class Ui_CertificateErrorDialog(object):
 
         self.m_infoLabel = QLabel(CertificateErrorDialog)
         self.m_infoLabel.setObjectName(u"m_infoLabel")
-        sizePolicy1 = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
+        sizePolicy1 = QSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.MinimumExpanding)
         sizePolicy1.setHorizontalStretch(0)
         sizePolicy1.setVerticalStretch(0)
         sizePolicy1.setHeightForWidth(self.m_infoLabel.sizePolicy().hasHeightForWidth())
@@ -57,7 +57,7 @@ class Ui_CertificateErrorDialog(object):
 
         self.verticalLayout.addWidget(self.m_infoLabel)
 
-        self.verticalSpacer = QSpacerItem(20, 16, QSizePolicy.Minimum, QSizePolicy.Expanding)
+        self.verticalSpacer = QSpacerItem(20, 16, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
 
         self.verticalLayout.addItem(self.verticalSpacer)
 
index 0f98831d44caac5b72fca6d3140efe9abab43ea0..f0f61aa75aaf22f341aef03df5ee71bda7903802 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'downloadmanagerwidget.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -49,7 +49,7 @@ class Ui_DownloadManagerWidget(object):
         self.m_itemsLayout.setContentsMargins(3, 3, 3, 3)
         self.m_zeroItemsLabel = QLabel(self.m_items)
         self.m_zeroItemsLabel.setObjectName(u"m_zeroItemsLabel")
-        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.m_zeroItemsLabel.sizePolicy().hasHeightForWidth())
index 3522f07589cbdbe34931e66e7a6cf8fec536c6cb..58c32fdf88b2bf45836e141918060a6adedda28d 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'downloadwidget.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -40,7 +40,7 @@ class Ui_DownloadWidget(object):
 
         self.m_cancelButton = QPushButton(DownloadWidget)
         self.m_cancelButton.setObjectName(u"m_cancelButton")
-        sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.m_cancelButton.sizePolicy().hasHeightForWidth())
index 6a40f30e60666dc513b43d6044b24ba95ae78174..11e0c4a2e0acec2dc67881d07cedd2658067124e 100644 (file)
@@ -3,7 +3,7 @@
 ################################################################################
 ## Form generated from reading UI file 'passworddialog.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.5.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -34,7 +34,7 @@ class Ui_PasswordDialog(object):
 
         self.m_infoLabel = QLabel(PasswordDialog)
         self.m_infoLabel.setObjectName(u"m_infoLabel")
-        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.m_infoLabel.sizePolicy().hasHeightForWidth())
index 84d24833bfca81db40935ff56b9be32c8b36bb19..e1282c1dd6e5a67c03f5cd5b93f24c49b6f82c98 100644 (file)
@@ -55,7 +55,8 @@ class WebView(QWebEngineView):
         self.renderProcessTerminated.connect(self._render_process_terminated)
 
         self._error_icon = QIcon(":dialog-error.png")
-        self._loading_icon = QIcon(":view-refresh.png")
+        self._loading_icon = QIcon.fromTheme(QIcon.ThemeIcon.ViewRefresh,
+                                             QIcon(":view-refresh.png"))
         self._default_icon = QIcon(":text-html.png")
 
     @Slot()
index 5fee93c8c75a2310ad6f47c5f062647ad9c8011a..910961b1e473a2fc042f49a18a9c2b2bbff2cc3d 100644 (file)
@@ -1,7 +1,5 @@
-# WigglyWidget
-
-The original Qt/C++ example can be found here:
-https://doc.qt.io/qt-6/qtwidgets-widgets-wiggly-example.html
+(widgetbinding-example)=
+# WigglyWidget Example
 
 This example shows how to interact with a custom widget from two
 different ways:
@@ -42,20 +40,24 @@ The most important files are:
 Now create a `build/` directory, and from inside run `cmake` to use
 the provided `CMakeLists.txt`:
 
-macOS/Linux:
+Run CMake on macOS/Linux:
 ```bash
 cd ~/pyside-setup/examples/widgetbinding
+cd build
+cmake .. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release
 ```
 
-On Windows:
+Run CMake on Windows:
 ```bash
 cd C:\pyside-setup\examples\widgetbinding
+mkdir build
+cd build
+cmake .. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=cl.exe
 ```
 
+To build:
 ```bash
-mkdir build
-cd build
-cmake -H.. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release
+
 ninja
 ninja install
 cd ..
index 0ff7a15472eccdc033a8145d0a1dd36bb293a18f..2925cbae70d4cdbf92b16b2fac55128a5c59118e 100644 (file)
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 
 ################################################################################
-## Form generated from reading UI file 'form2.ui'
+## Form generated from reading UI file 'form.ui'
 ##
-## Created by: Qt User Interface Compiler version 6.4.0
+## Created by: Qt User Interface Compiler version 6.7.0
 ##
 ## WARNING! All changes made in this file will be lost when recompiling UI file!
 ################################################################################
@@ -29,7 +29,7 @@ class Ui_Form(object):
         self.gridLayout.setObjectName(u"gridLayout")
         self.easingCurvePicker = QListWidget(Form)
         self.easingCurvePicker.setObjectName(u"easingCurvePicker")
-        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
+        sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.easingCurvePicker.sizePolicy().hasHeightForWidth())
@@ -73,7 +73,7 @@ class Ui_Form(object):
 
         self.groupBox = QGroupBox(Form)
         self.groupBox.setObjectName(u"groupBox")
-        sizePolicy1 = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
+        sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
         sizePolicy1.setHorizontalStretch(0)
         sizePolicy1.setVerticalStretch(0)
         sizePolicy1.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth())
@@ -83,7 +83,7 @@ class Ui_Form(object):
         self.formLayout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
         self.label = QLabel(self.groupBox)
         self.label.setObjectName(u"label")
-        sizePolicy2 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+        sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
         sizePolicy2.setHorizontalStretch(0)
         sizePolicy2.setVerticalStretch(0)
         sizePolicy2.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
@@ -95,7 +95,7 @@ class Ui_Form(object):
         self.periodSpinBox = QDoubleSpinBox(self.groupBox)
         self.periodSpinBox.setObjectName(u"periodSpinBox")
         self.periodSpinBox.setEnabled(False)
-        sizePolicy3 = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
+        sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
         sizePolicy3.setHorizontalStretch(0)
         sizePolicy3.setVerticalStretch(0)
         sizePolicy3.setHeightForWidth(self.periodSpinBox.sizePolicy().hasHeightForWidth())
@@ -142,7 +142,7 @@ class Ui_Form(object):
 
         self.verticalLayout.addWidget(self.groupBox)
 
-        self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
+        self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
 
         self.verticalLayout.addItem(self.verticalSpacer)
 
@@ -151,7 +151,7 @@ class Ui_Form(object):
 
         self.graphicsView = QGraphicsView(Form)
         self.graphicsView.setObjectName(u"graphicsView")
-        sizePolicy4 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
         sizePolicy4.setHorizontalStretch(0)
         sizePolicy4.setVerticalStretch(0)
         sizePolicy4.setHeightForWidth(self.graphicsView.sizePolicy().hasHeightForWidth())
index 2b08ae5770851eb0130ea892fd21e8e957243796..6ca287c2033663611b65bb58ca6b08fc309b9d7f 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE RCC><RCC version="1.0">
-<qresource>
-    <file>translations/example_de.qm</file>
+<qresource prefix="translations">
+    <file>example_de.qm</file>
 </qresource>
 </RCC>
index 7b2fa067254679b051e1c7e22278d0043ebbb62a..f69eade2e2486bb2a052490b6cd9ce993cb48708 100644 (file)
@@ -82,16 +82,16 @@ class MainWindow(QMainWindow):
         self.setWindowModified(self._text_edit.document().isModified())
 
     def create_actions(self):
-        icon = QIcon.fromTheme("document-new", QIcon(':/images/new.png'))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentNew, QIcon(':/images/new.png'))
         self._new_act = QAction(icon, "&New", self, shortcut=QKeySequence.New,
                                 statusTip="Create a new file", triggered=self.new_file)
 
-        icon = QIcon.fromTheme("document-open", QIcon(':/images/open.png'))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentOpen, QIcon(':/images/open.png'))
         self._open_act = QAction(icon, "&Open...", self,
                                  shortcut=QKeySequence.Open, statusTip="Open an existing file",
                                  triggered=self.open)
 
-        icon = QIcon.fromTheme("document-save", QIcon(':/images/save.png'))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentSave, QIcon(':/images/save.png'))
         self._save_act = QAction(icon, "&Save", self,
                                  shortcut=QKeySequence.Save,
                                  statusTip="Save the document to disk", triggered=self.save)
@@ -101,28 +101,30 @@ class MainWindow(QMainWindow):
                                     statusTip="Save the document under a new name",
                                     triggered=self.save_as)
 
-        self._exit_act = QAction("E&xit", self, shortcut="Ctrl+Q",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.ApplicationExit)
+        self._exit_act = QAction(icon, "E&xit", self, shortcut="Ctrl+Q",
                                  statusTip="Exit the application", triggered=self.close)
 
-        icon = QIcon.fromTheme("edit-cut", QIcon(':/images/cut.png'))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditCut, QIcon(':/images/cut.png'))
         self._cut_act = QAction(icon, "Cu&t", self, shortcut=QKeySequence.Cut,
                                 statusTip="Cut the current selection's contents to the clipboard",
                                 triggered=self._text_edit.cut)
 
-        icon = QIcon.fromTheme("edit-copy", QIcon(':/images/copy.png'))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditCopy, QIcon(':/images/copy.png'))
         self._copy_act = QAction(icon, "&Copy",
                                  self, shortcut=QKeySequence.Copy,
                                  statusTip="Copy the current selection's contents to the clipboard",
                                  triggered=self._text_edit.copy)
 
-        icon = QIcon.fromTheme("edit-paste", QIcon(':/images/paste.png'))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditPaste, QIcon(':/images/paste.png'))
         self._paste_act = QAction(icon, "&Paste",
                                   self, shortcut=QKeySequence.Paste,
                                   statusTip="Paste the clipboard's contents into the current "
                                   "selection",
                                   triggered=self._text_edit.paste)
 
-        self._about_act = QAction("&About", self,
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.HelpAbout)
+        self._about_act = QAction(icon, "&About", self,
                                   statusTip="Show the application's About box",
                                   triggered=self.about)
 
index 92c0c9c2b7af423fa83637d134534f33d9a4fda6..c1fa01b8cf2b8379e74b2d9f0660455d1f7b808f 100644 (file)
@@ -271,17 +271,17 @@ class MainWindow(QMainWindow):
 
     def create_actions(self):
 
-        icon = QIcon.fromTheme("document-new")
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentNew)
         self._new_act = QAction(icon, "&New", self,
                                 shortcut=QKeySequence.New, statusTip="Create a new file",
                                 triggered=self.new_file)
 
-        icon = QIcon.fromTheme("document-open")
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentOpen)
         self._open_act = QAction(icon, "&Open...", self,
                                  shortcut=QKeySequence.Open, statusTip="Open an existing file",
                                  triggered=self.open)
 
-        icon = QIcon.fromTheme("document-save")
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentSave)
         self._save_act = QAction(icon, "&Save", self,
                                  shortcut=QKeySequence.Save,
                                  statusTip="Save the document to disk", triggered=self.save)
@@ -291,23 +291,24 @@ class MainWindow(QMainWindow):
                                     statusTip="Save the document under a new name",
                                     triggered=self.save_as)
 
-        self._exit_act = QAction("E&xit", self, shortcut=QKeySequence.Quit,
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.ApplicationExit)
+        self._exit_act = QAction(icon, "E&xit", self, shortcut=QKeySequence.Quit,
                                  statusTip="Exit the application",
                                  triggered=QApplication.instance().closeAllWindows)
 
-        icon = QIcon.fromTheme("edit-cut")
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditCut)
         self._cut_act = QAction(icon, "Cu&t", self,
                                 shortcut=QKeySequence.Cut,
                                 statusTip="Cut the current selection's contents to the clipboard",
                                 triggered=self.cut)
 
-        icon = QIcon.fromTheme("edit-copy")
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditCopy)
         self._copy_act = QAction(icon, "&Copy", self,
                                  shortcut=QKeySequence.Copy,
                                  statusTip="Copy the current selection's contents to the clipboard",
                                  triggered=self.copy)
 
-        icon = QIcon.fromTheme("edit-paste")
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditPaste)
         self._paste_act = QAction(icon, "&Paste", self,
                                   shortcut=QKeySequence.Paste,
                                   statusTip="Paste the clipboard's contents into the current "
@@ -341,7 +342,8 @@ class MainWindow(QMainWindow):
         self._separator_act = QAction(self)
         self._separator_act.setSeparator(True)
 
-        self._about_act = QAction("&About", self,
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.HelpAbout)
+        self._about_act = QAction(icon, "&About", self,
                                   statusTip="Show the application's About box",
                                   triggered=self.about)
 
diff --git a/examples/widgets/rhi/simplerhiwidget/doc/simplerhiwidget.rst b/examples/widgets/rhi/simplerhiwidget/doc/simplerhiwidget.rst
new file mode 100644 (file)
index 0000000..c33c666
--- /dev/null
@@ -0,0 +1,34 @@
+.. _rhi-widget-example:
+
+Simple RHI Widget Example
+=========================
+
+Shows how to render a triangle using ``QRhi``, Qt's 3D API and shading
+language abstraction layer.
+
+This example is, in many ways, the counterpart of the :ref:`rhi-window-example`
+in the QWidget world. The ``QRhiWidget`` subclass in this applications renders
+a single triangle, using a simple graphics pipeline with basic vertex and
+fragment shaders. Unlike the plain ``QWindow``-based application, this example
+does not need to worry about lower level details, such as setting up the window
+and the ``QRhi``, or dealing with swapchain and window events, as that is taken
+care of by the ``QWidget`` framework here. The instance of the ``QRhiWidget``
+subclass is added to a ``QVBoxLayout``. To keep the example minimal and
+compact, there are no further widgets or 3D content introduced.
+
+Once an instance of ``ExampleRhiWidget``, a ``QRhiWidget`` subclass, is added
+to a top-level widget's child hierarchy, the corresponding window automatically
+becomes a Direct 3D, Vulkan, Metal, or OpenGL-rendered window. The
+``QPainter``-rendered widget content, i.e. everything that is not a
+``QRhiWidget``, ``QOpenGLWidget``, or ``QQuickWidget``, is then uploaded to a
+texture, whereas the mentioned special widgets each render to a texture. The
+resulting set textures is composited together by the top-level widget's
+backingstore.
+
+As opposed to the C++ example, the cleanup is done by reimplementing
+``QRhiWidget.releaseResources()``, which is called from QWidget.closeEvent() of
+the top level widget to ensure a deterministic cleanup sequence.
+
+.. image:: simplerhiwidget.webp
+   :width: 400
+   :alt: Screenshot of the Simple RHI Widget example
diff --git a/examples/widgets/rhi/simplerhiwidget/doc/simplerhiwidget.webp b/examples/widgets/rhi/simplerhiwidget/doc/simplerhiwidget.webp
new file mode 100644 (file)
index 0000000..fdb8d20
Binary files /dev/null and b/examples/widgets/rhi/simplerhiwidget/doc/simplerhiwidget.webp differ
diff --git a/examples/widgets/rhi/simplerhiwidget/examplewidget.py b/examples/widgets/rhi/simplerhiwidget/examplewidget.py
new file mode 100644 (file)
index 0000000..5b3e40f
--- /dev/null
@@ -0,0 +1,135 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import numpy
+
+from PySide6.QtCore import (QFile, QIODevice)
+from PySide6.QtGui import (QColor, QMatrix4x4)
+from PySide6.QtGui import (QRhiBuffer,
+                           QRhiDepthStencilClearValue,
+                           QRhiShaderResourceBinding,
+                           QRhiShaderStage,
+                           QRhiVertexInputAttribute, QRhiVertexInputBinding,
+                           QRhiVertexInputLayout, QRhiViewport,
+                           QShader)
+from PySide6.QtWidgets import QRhiWidget
+from PySide6.support import VoidPtr
+
+VERTEX_DATA = numpy.array([ 0.0,  0.5, 1.0, 0.0, 0.0,  # noqa E:201
+                           -0.5, -0.5, 0.0, 1.0, 0.0,  # noqa E:241
+                            0.5, -0.5, 0.0, 0.0, 1.0],
+                          dtype=numpy.float32)
+
+
+def getShader(name):
+    f = QFile(name)
+    if f.open(QIODevice.ReadOnly):
+        return QShader.fromSerialized(f.readAll())
+    return QShader()
+
+
+class ExampleRhiWidget(QRhiWidget):
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.m_rhi = None
+        self.m_vbuf = None
+        self.m_ubuf = None
+        self.m_srb = None
+        self.m_pipeline = None
+        self.m_viewProjection = QMatrix4x4()
+        self.m_rotation = 0.0
+
+    def releaseResources(self):
+        self.m_pipeline.destroy()
+        del self.m_pipeline
+        self.m_pipeline = None
+        self.m_srb.destroy()
+        del self.m_srb
+        self.m_srb = None
+        self.m_ubuf.destroy()
+        del self.m_ubuf
+        self.m_ubuf = None
+        self.m_vbuf.destroy()
+        del self.m_vbuf
+        self.m_buf = None
+
+    def initialize(self, cb):
+        if self.m_rhi != self.rhi():
+            self.m_pipeline = None
+            self.m_rhi = self.rhi()
+
+        if not self.m_pipeline:
+            vertex_size = 4 * VERTEX_DATA.size
+            self.m_vbuf = self.m_rhi.newBuffer(QRhiBuffer.Immutable,
+                                               QRhiBuffer.VertexBuffer, vertex_size)
+            self.m_vbuf.create()
+
+            self.m_ubuf = self.m_rhi.newBuffer(QRhiBuffer.Dynamic,
+                                               QRhiBuffer.UniformBuffer, 64)
+            self.m_ubuf.create()
+
+            self.m_srb = self.m_rhi.newShaderResourceBindings()
+            bindings = [
+                QRhiShaderResourceBinding.uniformBuffer(0, QRhiShaderResourceBinding.VertexStage,
+                                                        self.m_ubuf)
+            ]
+            self.m_srb.setBindings(bindings)
+            self.m_srb.create()
+
+            self.m_pipeline = self.m_rhi.newGraphicsPipeline()
+            stages = [
+                QRhiShaderStage(QRhiShaderStage.Vertex,
+                                getShader(":/shader_assets/color.vert.qsb")),
+                QRhiShaderStage(QRhiShaderStage.Fragment,
+                                getShader(":/shader_assets/color.frag.qsb"))
+            ]
+            self.m_pipeline.setShaderStages(stages)
+            inputLayout = QRhiVertexInputLayout()
+            input_bindings = [QRhiVertexInputBinding(5 * 4)]  # sizeof(float)
+            inputLayout.setBindings(input_bindings)
+            attributes = [  # 4: sizeof(float)
+                QRhiVertexInputAttribute(0, 0, QRhiVertexInputAttribute.Float2, 0),
+                QRhiVertexInputAttribute(0, 1, QRhiVertexInputAttribute.Float3, 2 * 4)
+            ]
+            inputLayout.setAttributes(attributes)
+            self.m_pipeline.setVertexInputLayout(inputLayout)
+            self.m_pipeline.setShaderResourceBindings(self.m_srb)
+            self.m_pipeline.setRenderPassDescriptor(self.renderTarget().renderPassDescriptor())
+            self.m_pipeline.create()
+
+            resourceUpdates = self.m_rhi.nextResourceUpdateBatch()
+            resourceUpdates.uploadStaticBuffer(self.m_vbuf, VoidPtr(VERTEX_DATA.tobytes(),
+                                                                    vertex_size))
+            cb.resourceUpdate(resourceUpdates)
+
+        outputSize = self.renderTarget().pixelSize()
+        self.m_viewProjection = self.m_rhi.clipSpaceCorrMatrix()
+        r = float(outputSize.width()) / float(outputSize.height())
+        self.m_viewProjection.perspective(45.0, r, 0.01, 1000.0)
+        self.m_viewProjection.translate(0, 0, -4)
+
+    def render(self, cb):
+        resourceUpdates = self.m_rhi.nextResourceUpdateBatch()
+        self.m_rotation += 1.0
+        modelViewProjection = self.m_viewProjection
+        modelViewProjection.rotate(self.m_rotation, 0, 1, 0)
+        projection = numpy.array(modelViewProjection.data(),
+                                 dtype=numpy.float32)
+        resourceUpdates.updateDynamicBuffer(self.m_ubuf, 0, 64,
+                                            projection.tobytes())
+        clearColor = QColor.fromRgbF(0.4, 0.7, 0.0, 1.0)
+        cv = QRhiDepthStencilClearValue(1.0, 0)
+        cb.beginPass(self.renderTarget(), clearColor, cv, resourceUpdates)
+
+        cb.setGraphicsPipeline(self.m_pipeline)
+        outputSize = self.renderTarget().pixelSize()
+        cb.setViewport(QRhiViewport(0, 0, outputSize.width(),
+                                    outputSize.height()))
+        cb.setShaderResources()
+        vbufBinding = (self.m_vbuf, 0)
+        cb.setVertexInput(0, [vbufBinding])
+        cb.draw(3)
+        cb.endPass()
+
+        self.update()
diff --git a/examples/widgets/rhi/simplerhiwidget/main.py b/examples/widgets/rhi/simplerhiwidget/main.py
new file mode 100644 (file)
index 0000000..59be81d
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+"""PySide6 port of the Qt Simple RHI Widget Example example from Qt v6.x"""
+
+import sys
+
+from PySide6.QtWidgets import QApplication, QVBoxLayout, QWidget
+
+from examplewidget import ExampleRhiWidget
+import rc_simplerhiwidget  # noqa F:401
+
+
+class Widget(QWidget):
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        layout = QVBoxLayout(self)
+        self._rhi_widget = ExampleRhiWidget(self)
+        layout.addWidget(self._rhi_widget)
+
+    def closeEvent(self, e):
+        self._rhi_widget.releaseResources()
+        e.accept()
+
+
+if __name__ == "__main__":
+    app = QApplication(sys.argv)
+
+    w = Widget()
+    w.resize(1280, 720)
+    w.show()
+    exit_code = app.exec()
+    del w
+    sys.exit(exit_code)
diff --git a/examples/widgets/rhi/simplerhiwidget/rc_simplerhiwidget.py b/examples/widgets/rhi/simplerhiwidget/rc_simplerhiwidget.py
new file mode 100644 (file)
index 0000000..ee8b412
--- /dev/null
@@ -0,0 +1,163 @@
+# Resource object code (Python 3)
+# Created by: object code
+# Created by: The Resource Compiler for Qt version 6.7.0
+# WARNING! All changes made in this file will be lost!
+
+from PySide6 import QtCore
+
+qt_resource_data = b"\
+\x00\x00\x02\xe2\
+\x00\
+\x00\x07\xc4x\x9c\xb5T]k\xd4@\x14\x9d\xed\xa6]\
+\x9b\xd6\xda\x0f\xd07\x19\xe9\xcb\x16%\xa6\xb5\x15q\xdd\
+\xfa\xb0U)\x14Z\xdbR\x84e\x091\x9bM\x07\xb2\
+\xc9\x92\x8fE)\x05\xdf}\xf7w\xf8'\xfcO\xbe\x88\
+\xde;s\xd3\xcc\xa6[*\x88\x03\xb3\x999s\xef=\
+g\xceM\x9616\xcf\x183`\xd6`.\xb11s\
+\x98\xc7b\x16\xc2L\x00\xa9\xc3d\xbfi\xb0)\x03\xd3\
+V\xd9\x00\x82]\x16\xb0\x8e\x96j\xdc\x96\xfa\xafc\x8e\
+\x9e}M\xcd\xf7\xfa\xccz\x03U\x99\xec\x0e[#t\
+\x85\xcdH\x9d\x0b\x90\x82\xcfw\x07'\x07V\x9a\xf5\xad\
+\xed\x1d\x1b\xcf\x97\xd45\xe5\xd9=\xd6\x90\xcaq\x0e]\
+\x11!\x8e\x16-\xc2\x5c\x868\xc4\x1bX\x03V\x88?\
+$\x0e\xdc/j\xfb5\xe0\x9c\x81\xe7#\xc8\xc1\xea\xb8\
+\xbe\x0f+\x14\xcda>\x80\xf8\x06]\xc2\x90\x98\x01\x8a\
+\x95\xe1\x88\xb7h?O\x18\xc6\x9b\x14_\xa7\xf8\x05\xd2\
+lR\xfc\x02\xe9D\xec1\xec\xe7\xe4\xddp|y\xfd\
+\x9c\xcdJ\x0d\x06\xe9\xc3\x1a?\x01\x99\x85g\x9bj\xdf\
+\xa5\xfc\xf7\x80\xceI/\x14\xc64l\x99\xb0\x9a\x86\xad\
+\x10\x86\xf5\x8f@=\xea_\xa5\xfce:G\x1d\xbb\xc0\
+:Og\xbf\xa0\xc2\x0bY\x85\x19\xe4s\x8dzY#\
+\xca\xaf\xebc?IE\x1c\xf1M\xdb6G\x89\xef\x09\
+\xb9;\x17\xc1\xf9\x88\x0f\xc2\xd8\xcdZ\xd7`\x11\x01h\
+\x8e\xdd\xe4\xb3\x88\x02>\xf6\xbdg|\xecxq\x18'\
+\x08\xc7\xa2\xcf\x91\xad\xb9a^\x98\x1cF\x10:o\x13\
+7\xd8s3\xb7k\xf7x\x1b3\xb6\x9b\x94\xf1\x84o\
+Z\xf6F\xcb\xbc4\xcd\x8a\xccO\xe5+\xc7\x9cR\xe6\
+\x96\xfd\xff\xa9\xbfi\xd4\xa2\xa4\xde\x01\xea8\xcfd\x11\
+>\x80\xba\x1dE,\xa2\xdb\x95\x5c\x85\xff\x95\x08\xec\xf2\
+V\xa9\xa1\xf6#\xcd\xdcLx\xaa!\x13\xdc\xfa\x81\xae\
+ \xcd\x92\xdc\xcb\xf8\xc9\xd1\xfe\xf1\x99\xd3I\xe24u\
+\xf6\xa3Q\x9e\x15r&\xe2\xf9K~\xfa\xe6C\xe7\xf0\
+\xf0x\xcf\x06)\xd3\xd3\x0f\xf3\xac\x92\xaf\x09\x81\x0a'\
+g\xce\xa9\x9b\x04~F%\xa4\x07\x18\xe0\xdch\x84\xaa\
+2a\xc5@yq\x9dX\xd9y\xed>\x1c\x0c\x08|\
+G\xe0\xba\xa0(n\xd5\xd6\x0f\xad+o\x0a\x15\xa4K\
+\x01S\x08Ur,7*HG\xac\x89\x8b\x94\x0d\xc1\
+\xb8\xc4\xcf\xf2$\xaa\x14\xb8\xd4\x1bl\xd0\xdf@\xd1\xe0\
+\xfdu\x11ya\xde\xf7\xf9\xab\xa1\x9f\xb9\xa1\x03\x7f\x9d\
+\xa1\xf8\xb8k\x96x*\x86\xfd\xa7\xf8c\x9d\xef\x9af\
+\x9e\xe2\x07\x10\xb9C?\x1d\xb9\x9e\xcfeV\xd98\xa4\
+\xb1\x91\xfa\xa6~u\xbb\xd2\x8d\xa6\xbd\xd1\xebM\xb4\x5c\
+e\x8ah\xfa\x8b\xd2\xed\xe6\xa9\x9f4\xc3\xd8\x8b\xcaL\
+\xac:\xf4#\x8dU\xad\x9aE-\xf8\xc7\x80\xcc\xa2\x19\
+\xbd^\xd1\xa82\x1eg\x9b_\x5c*\xff\xe2\xaa\xbd\xea\
+=\x11\x91U\xf9j4\xb3c\xe51\x9a<+\xeb\xd2\
+gT\xf9\x94\xe4\xa8\xb8_\xb6\xe1\xa6\xb3?Y\xbd\xa1\
+\xc8\
+\x00\x00\x04C\
+\x00\
+\x00\x0c\xf4x\x9c\xddW[o\x1bE\x14\x1e_\x92\x92\
+-\xb9\xb4i\x93\x16\xda2\xa9%dCe\x9c4A\
+\xa8&\x11\xa8 Z\xa9R\xaa\x06UHV\xb4Z\xaf\
+\xd7\xe9\xc2^\xac\xddY7\xa8\xf2\x8f\xe0\x85\xbf\xc3o\
+\xe0o\xf0\xc8\x13/U9g\xe6\xcc\xee\xec\xda\xa1*\
+\x0f<0\xd2d\xe7\x5c\xe6|\xe7|sf\x920\xc6\
+V\x98\x1au\x98\x16sY\xcc\x02\x98\x09H\x0d\x98\xb5\
+74\xd8\x82\xb1\xc1&\xe0\x9a2\x9f\x09\x981\x8b@\
+\xd7D\xc3?m\xaa\xc1\x5ccSf\xcfa\xbdu\xdb\
+2\x1b\xb2\x8c\x8d\xe5\xcaf{\xec\x00V_\xcd\xf9\x84\
+\x10|\x02\xab\xcb\xa45=6\x16\x85~\x97Q\xa3o\
+\x93\xbe\xcb\xf4\x1d\x15.\x8d\x17\x8dz\xeb\x12\xbaZ\xec\
+=\xd6\x22\xed\x15 \xb8&\xb3Z\x96\xdf\xef\x9e\x9c<\
+\xe9\xa6b\xd4\xdd?\xe8\xa1}MQ m\xebt(\
+\x08\x12:>\xd2*5X\xd1&\xcc;\xb8\x1f\xac+\
+\xb4f$_&\x19c<bK\x80\xa9\x86fB\xeb\
+j\xa43\xfd\xea\xa4k\xc8X\x8d\x5c\xf7\x08\xe2n\xd3\
+\xfe%\xf2\xd7r\xcb\x88\xabuP\xb8d\x19clS\
+\x0c\xcc\xed&|\xef\x1a\xb9\xa2\xbcc\xc8w\x8cZ6\
+aW]\xda\x1b2\x1f\x5co\xc1\x0a\xc9\xe60\xb7\xc1\
+\xff\x12\x91\xdf\x90\xba&0\xad\xd6\xa8\xef\x93\xbcb\xd8\
+-\xaaW\xdb-\x83\x03\x8c\xb7J\xf1\x90\xf3\xeb\xf0s\
+\x8d\xb0p|J\xf2:\xf9\xdf\x02y\x83\xfc\xd7e\xde\
+\x8aC\x1dc\x830\xaf\x12\xfe\x15\xc2\xbcJ\xe7\xd7 \
+\x8ck\x84Q#\x8ckR\xaf\xc6\x0d\x90\xb7(fS\
+b(>\xb7(\xf6\x0d\xe2e\x9bb\xa3|\x93th\
+\xff \xe7M\xc9\xb7\x09g\x95\xfco\xb3\xa2W\xd0\xbe\
+Cy\xa1\xfds\xa8\xa7\xce\x8a&G\xfd_\xa0\xc1\xf3\
+?$\xee\xdf'\xfe\x8e\xc0\xbaB\xf2\xd7\xe0\x81\xb8\x1f\
+R.\xd7\xc9\x7fKr\xa6\xf4\x87\xc4\xf5G\x84\xff\x0b\
+\xecY%\x1en\x91\x1e\xe3\xecP\xbflR\x1c\xc4\xb9\
+K~\xaf!\xeb/\xd4Ul\xd2\xfd@a\xc4\x8a\xfb\
+\xf9{k\xea%\xa9\x1fG|\xb7\xd7\xb3\xacT$\x99\
++\xf80\x1b[\xaf,\x0e#t\xc4>\x0f\xa7\x93\xbe\
+5\xeb[V\x16\xf9\xe38\x09\xd1\xce\xed\xbd\x03\xd0L\
+\x9d\xe4g?:\xe3S\xcf\xbd\xcf\xa7\xb6\x1b\x07q\xd2\
+\xb7\x1c!\x12\x7f\x98\x09O\xe9\x17i\xf7\xf9$N}\
+\x01\xc8\x18%\xf6G\x1c3lw\x08\x97B\xf1C\xbd\
+\x19\x95g\x81\xfd\x946\x81\x01\x12\xe8Bf\xfc\x13#\
+\xd2\xcc\xb2*\xc5\x9e\xb3b\x18\xc5\xee\xfd/\x8b\xfd\xd5\
+(\xf6\xb7\xa2\xd8\x83\x7fSl\x9c\x89J\xa1~T\xaa\
+P\x89\xffEix\xc7\xf6\x8a\xca\xea\x7f\xb8\x90\xe6\xd8\
+Kd\xb6\x0fx\xe2\x9d\xf9\xa9\xf0\x92\xf6\xb0\xa7a\x93\
+\xf8\xa5\x1d:?\x02\xf08\x88\xa1\xd0\xf3}\x84\xb1\x11\
+\xe6\x01\x9f8\xeeO\xf1x\x9cz\xa2\xed\xf6:\xaa~\
+\xe0\xc7\x11\xbeK\xeef\x86\xfd\x92\xc9\xa0\xa3\xac^\xa0\
+,QC\xfc\x9f<}\xfc\xec\xb9\xfd0\x89\xd3\xd4~\
+\x1cM2A\x09W6@\x96\xdf\x7f\xfb\xc3\xc3\xe3\xe3\
+g\xdf\xf4\xfa\x85\x03\xc1\x18\xd6]\x95\xfe\x82\xe8\xc7\x99\
+\xa8\x84\xcfs\xbf z\xa9l\xf09yn\x900\xd3\
+\xc7\x0b]%\xecw=\xe30\x0b\xda\xba\xb6{\xfa(\
+:\xf2\x9c\xe7sV\x1d4\xc7\x14\x07n\xcf<\xdb\xc7\
+\xb5\x86\xd6\xc0\x86\xa9k$1)20=\x8ac\x91\
+\xe9\x17\x05)\xc5\x82\x8c\xd4\xeeX\x0a\xca\xc9\xd4t\xcb\
+\xc5\x96\x9ag\xce\xb7`+\xef$\xd9\xb1\x9e\xc8\x92\xa8\
+\x0243oA\x93~{\xd0\xa8\xfd\xd9\xf2#7\xc8\
+F\x1e\xff2\xf4\x84\x13\xd8\xf0WR\xe0\x0f\x8f\xacB\
+\x9f\xfa\xe1\xe83\xfc\xd1}q\x04w<\xc5\xc7+r\
+B/\x85+\xe0q\xb9\xab\xbf\xe0i\xc8\xefL\xfe<\
+\x90\x0bf\xd2\xc3\xec\x16\xb7\xd5`\x90\xa5p\x0d\x83\xd8\
+\x8dz\x9d\xd3\xd3\x0b[k0\xd0'\x80Ns\xf1\xfd\
+\xe8\x82K1\x18\xe4\xafj\xbb\x02\xa0o\x86\xe9\xb2\xdb\
+\xd1\xe1\xf1\x88\xbd\xf3\x22}\xb5jk8\xeecl\xdd\
+!\xa7\xa7\xf7 X\x04b$I\xf9\x18\xfb\x15\xec\xea\
+\xcd\x91\xc0\x9d\xfc\x0d\xd5\x01q\x1e\xf2W3\x95R\x5c\
+:g?2{2\x9e\xeb\x97\xe2\x01\x04\xcfroR\
+W\xc4\xaa\x19\xb0\x1b\x96$&=\x8a\x95\x871\xff\xad\
+\xce\xe8\xbf\x83J\xcb\xcc\xd9\xb5\xae\xea'\xc7\xdf%\xe1\
+\xb4\xa2\
+"
+
+qt_resource_name = b"\
+\x00\x0d\
+\x06E\xc5\xd3\
+\x00s\
+\x00h\x00a\x00d\x00e\x00r\x00_\x00a\x00s\x00s\x00e\x00t\x00s\
+\x00\x0e\
+\x04\x16\xeb\xb2\
+\x00c\
+\x00o\x00l\x00o\x00r\x00.\x00f\x00r\x00a\x00g\x00.\x00q\x00s\x00b\
+\x00\x0e\
+\x00\xfb\xe9\x92\
+\x00c\
+\x00o\x00l\x00o\x00r\x00.\x00v\x00e\x00r\x00t\x00.\x00q\x00s\x00b\
+"
+
+qt_resource_struct = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x02\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00B\x00\x00\x00\x00\x00\x01\x00\x00\x02\xe6\
+\x00\x00\x01\x8a!\x0c\xa5\xeb\
+\x00\x00\x00 \x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x01\x8a!\x0c\xa5\xeb\
+"
+
+def qInitResources():
+    QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+def qCleanupResources():
+    QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+qInitResources()
diff --git a/examples/widgets/rhi/simplerhiwidget/shader_assets/color.frag.qsb b/examples/widgets/rhi/simplerhiwidget/shader_assets/color.frag.qsb
new file mode 100644 (file)
index 0000000..32bd2d5
Binary files /dev/null and b/examples/widgets/rhi/simplerhiwidget/shader_assets/color.frag.qsb differ
diff --git a/examples/widgets/rhi/simplerhiwidget/shader_assets/color.vert.qsb b/examples/widgets/rhi/simplerhiwidget/shader_assets/color.vert.qsb
new file mode 100644 (file)
index 0000000..bf97035
Binary files /dev/null and b/examples/widgets/rhi/simplerhiwidget/shader_assets/color.vert.qsb differ
diff --git a/examples/widgets/rhi/simplerhiwidget/shaders/color.frag b/examples/widgets/rhi/simplerhiwidget/shaders/color.frag
new file mode 100644 (file)
index 0000000..3755876
--- /dev/null
@@ -0,0 +1,10 @@
+#version 440
+
+layout(location = 0) in vec3 v_color;
+
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+    fragColor = vec4(v_color, 1.0);
+}
diff --git a/examples/widgets/rhi/simplerhiwidget/shaders/color.vert b/examples/widgets/rhi/simplerhiwidget/shaders/color.vert
new file mode 100644 (file)
index 0000000..e876f29
--- /dev/null
@@ -0,0 +1,16 @@
+#version 440
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 color;
+
+layout(location = 0) out vec3 v_color;
+
+layout(std140, binding = 0) uniform buf {
+    mat4 mvp;
+};
+
+void main()
+{
+    v_color = color;
+    gl_Position = mvp * position;
+}
diff --git a/examples/widgets/rhi/simplerhiwidget/simplerhiwidget.pyproject b/examples/widgets/rhi/simplerhiwidget/simplerhiwidget.pyproject
new file mode 100644 (file)
index 0000000..ff0d627
--- /dev/null
@@ -0,0 +1,4 @@
+{
+    "files": ["main.py","examplewidget.py", "simplerhiwidget.qrc",
+              "shaders/color.frag", "shaders/color.vert"]
+}
diff --git a/examples/widgets/rhi/simplerhiwidget/simplerhiwidget.qrc b/examples/widgets/rhi/simplerhiwidget/simplerhiwidget.qrc
new file mode 100644 (file)
index 0000000..ddc6dfb
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+   <file>shader_assets/color.vert.qsb</file>
+   <file>shader_assets/color.frag.qsb</file>
+</qresource>
+</RCC>
index a3940ae0ff42b708b294dcb1fe044be28932babb..8019446f0a3f6180dcc22e8e2448e5d435841b3a 100644 (file)
@@ -101,13 +101,14 @@ class TextEdit(QMainWindow):
         tb = self.addToolBar("File self.actions")
         menu = self.menuBar().addMenu("&File")
 
-        icon = QIcon.fromTheme("document-new", QIcon(RSRC_PATH + "/filenew.png"))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentNew,
+                               QIcon(RSRC_PATH + "/filenew.png"))
         a = menu.addAction(icon, "&New", self.file_new)
         tb.addAction(a)
         a.setPriority(QAction.LowPriority)
         a.setShortcut(QKeySequence.New)
 
-        icon = QIcon.fromTheme("document-open",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentOpen,
                                QIcon(RSRC_PATH + "/fileopen.png"))
         a = menu.addAction(icon, "&Open...", self.file_open)
         a.setShortcut(QKeySequence.Open)
@@ -115,7 +116,7 @@ class TextEdit(QMainWindow):
 
         menu.addSeparator()
 
-        icon = QIcon.fromTheme("document-save",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentSave,
                                QIcon(RSRC_PATH + "/filesave.png"))
         self._action_save = menu.addAction(icon, "&Save", self.file_save)
         self._action_save.setShortcut(QKeySequence.Save)
@@ -126,7 +127,7 @@ class TextEdit(QMainWindow):
         a.setPriority(QAction.LowPriority)
         menu.addSeparator()
 
-        icon = QIcon.fromTheme("document-print",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentPrint,
                                QIcon(RSRC_PATH + "/fileprint.png"))
         a = menu.addAction(icon, "&Print...", self.file_print)
         a.setPriority(QAction.LowPriority)
@@ -151,32 +152,36 @@ class TextEdit(QMainWindow):
         tb = self.addToolBar("Edit self.actions")
         menu = self.menuBar().addMenu("&Edit")
 
-        icon = QIcon.fromTheme("edit-undo",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditUndo,
                                QIcon(RSRC_PATH + "/editundo.png"))
         self._action_undo = menu.addAction(icon, "&Undo", self._text_edit.undo)
         self._action_undo.setShortcut(QKeySequence.Undo)
         tb.addAction(self._action_undo)
 
-        icon = QIcon.fromTheme("edit-redo", QIcon(RSRC_PATH + "/editredo.png"))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditRedo,
+                               QIcon(RSRC_PATH + "/editredo.png"))
         self._action_redo = menu.addAction(icon, "&Redo", self._text_edit.redo)
         self._action_redo.setPriority(QAction.LowPriority)
         self._action_redo.setShortcut(QKeySequence.Redo)
         tb.addAction(self._action_redo)
         menu.addSeparator()
 
-        icon = QIcon.fromTheme("edit-cut", QIcon(RSRC_PATH + "/editcut.png"))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditCut,
+                               QIcon(RSRC_PATH + "/editcut.png"))
         self._action_cut = menu.addAction(icon, "Cu&t", self._text_edit.cut)
         self._action_cut.setPriority(QAction.LowPriority)
         self._action_cut.setShortcut(QKeySequence.Cut)
         tb.addAction(self._action_cut)
 
-        icon = QIcon.fromTheme("edit-copy", QIcon(RSRC_PATH + "/editcopy.png"))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditCopy,
+                               QIcon(RSRC_PATH + "/editcopy.png"))
         self._action_copy = menu.addAction(icon, "&Copy", self._text_edit.copy)
         self._action_copy.setPriority(QAction.LowPriority)
         self._action_copy.setShortcut(QKeySequence.Copy)
         tb.addAction(self._action_copy)
 
-        icon = QIcon.fromTheme("edit-paste", QIcon(RSRC_PATH + "/editpaste.png"))
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.EditPaste,
+                               QIcon(RSRC_PATH + "/editpaste.png"))
         self._action_paste = menu.addAction(icon, "&Paste", self._text_edit.paste)
         self._action_paste.setPriority(QAction.LowPriority)
         self._action_paste.setShortcut(QKeySequence.Paste)
@@ -190,7 +195,7 @@ class TextEdit(QMainWindow):
         tb = self.addToolBar("Format self.actions")
         menu = self.menuBar().addMenu("F&ormat")
 
-        icon = QIcon.fromTheme("format-text-bold",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatTextBold,
                                QIcon(RSRC_PATH + "/textbold.png"))
         self._action_text_bold = menu.addAction(icon, "&Bold", self.text_bold)
         self._action_text_bold.setShortcut(Qt.CTRL | Qt.Key_B)
@@ -201,7 +206,7 @@ class TextEdit(QMainWindow):
         tb.addAction(self._action_text_bold)
         self._action_text_bold.setCheckable(True)
 
-        icon = QIcon.fromTheme("format-text-italic",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatTextItalic,
                                QIcon(RSRC_PATH + "/textitalic.png"))
         self._action_text_italic = menu.addAction(icon, "&Italic", self.text_italic)
         self._action_text_italic.setPriority(QAction.LowPriority)
@@ -212,7 +217,7 @@ class TextEdit(QMainWindow):
         tb.addAction(self._action_text_italic)
         self._action_text_italic.setCheckable(True)
 
-        icon = QIcon.fromTheme("format-text-underline",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatTextUnderline,
                                QIcon(RSRC_PATH + "/textunder.png"))
         self._action_text_underline = menu.addAction(icon, "&Underline",
                                                      self.text_underline)
@@ -226,36 +231,36 @@ class TextEdit(QMainWindow):
 
         menu.addSeparator()
 
-        icon = QIcon.fromTheme("format-justify-left",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatJustifyLeft,
                                QIcon(RSRC_PATH + "/textleft.png"))
         self._action_align_left = QAction(icon, "&Left", self)
         self._action_align_left.setShortcut(Qt.CTRL | Qt.Key_L)
         self._action_align_left.setCheckable(True)
         self._action_align_left.setPriority(QAction.LowPriority)
-        icon = QIcon.fromTheme("format-justify-center",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatJustifyCenter,
                                QIcon(RSRC_PATH + "/textcenter.png"))
         self._action_align_center = QAction(icon, "C&enter", self)
         self._action_align_center.setShortcut(Qt.CTRL | Qt.Key_E)
         self._action_align_center.setCheckable(True)
         self._action_align_center.setPriority(QAction.LowPriority)
-        icon = QIcon.fromTheme("format-justify-right",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatJustifyRight,
                                QIcon(RSRC_PATH + "/textright.png"))
         self._action_align_right = QAction(icon, "&Right", self)
         self._action_align_right.setShortcut(Qt.CTRL | Qt.Key_R)
         self._action_align_right.setCheckable(True)
         self._action_align_right.setPriority(QAction.LowPriority)
-        icon = QIcon.fromTheme("format-justify-fill",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatJustifyFill,
                                QIcon(RSRC_PATH + "/textjustify.png"))
         self._action_align_justify = QAction(icon, "&Justify", self)
         self._action_align_justify.setShortcut(Qt.CTRL | Qt.Key_J)
         self._action_align_justify.setCheckable(True)
         self._action_align_justify.setPriority(QAction.LowPriority)
-        icon = QIcon.fromTheme("format-indent-more",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatIndentMore,
                                QIcon(RSRC_PATH + "/format-indent-more.png"))
         self._action_indent_more = menu.addAction(icon, "&Indent", self.indent)
         self._action_indent_more.setShortcut(Qt.CTRL | Qt.Key_BracketRight)
         self._action_indent_more.setPriority(QAction.LowPriority)
-        icon = QIcon.fromTheme("format-indent-less",
+        icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatIndentLess,
                                QIcon(RSRC_PATH + "/format-indent-less.png"))
         self._action_indent_less = menu.addAction(icon, "&Unindent",
                                                   self.unindent)
index 70eb85bf65f853ea10ec9c50714effd0b94d479b..7205ef57fee54bcc9c39aaea37c5f9fa456ef233 100644 (file)
@@ -2,6 +2,7 @@ sphinx==7.2.6
 sphinx-design==0.5.0
 sphinx-copybutton==0.5.2
 sphinx-tags==0.3.1
+sphinx-toolbox
 myst-parser==2.0.0
 # FIXME: Using fork in order to enable the 'collapse_navbar=True'
 # option for the sphinx-theme. Upstream proposal:
index 2b279db3b1e7e42c94e2520595259483c63039f2..65380e93b28a6cdedb905a33b25da5359b1d32e8 100644 (file)
@@ -1,5 +1,5 @@
 # Build dependencies
-setuptools==69.0.3
+setuptools==69.1.1
 packaging==23.2
 build==1.0.3
 wheel==0.42.0
@@ -11,6 +11,3 @@ numpy==1.26.3; python_version >= '3.9'
 
 # For examples
 PyOpenGL
-
-# For tests
-pyinstaller==3.6; platform_machine != 'aarch64'
index d8a353300ec9b8e8dd7002e3867c840d8880e2e2..e629ec570b900b04f8ffb4dbc0394cc87e92c4d6 100644 (file)
@@ -44,7 +44,10 @@ else()
                         "${TOOLS_PATH}/lupdate${CMAKE_EXECUTABLE_SUFFIX}"
                         "${TOOLS_PATH}/qmllint${CMAKE_EXECUTABLE_SUFFIX}"
                         "${TOOLS_PATH}/qmlformat${CMAKE_EXECUTABLE_SUFFIX}"
-                        "${TOOLS_PATH}/qmlls${CMAKE_EXECUTABLE_SUFFIX}")
+                        "${TOOLS_PATH}/qmlls${CMAKE_EXECUTABLE_SUFFIX}"
+                        "${TOOLS_PATH}/qsb${CMAKE_EXECUTABLE_SUFFIX}"
+                        "${TOOLS_PATH}/balsam${CMAKE_EXECUTABLE_SUFFIX}"
+                        "${TOOLS_PATH}/balsamui${CMAKE_EXECUTABLE_SUFFIX}")
 
         if (APPLE)
             list(APPEND directories "${TOOLS_PATH}/Assistant.app"
index 8ef59781fbd016008745df8ba8346f54ad77156b..75269d6228d26d77a340e689cbaf325d0967c87c 100644 (file)
@@ -8,8 +8,8 @@ import traceback
 from pathlib import Path
 from textwrap import dedent
 
-from deploy_lib import (setup_python, create_config_file, cleanup, install_python_dependencies,
-                        config_option_exists, MAJOR_VERSION)
+from deploy_lib import (create_config_file, cleanup, config_option_exists, PythonExecutable,
+                        MAJOR_VERSION, HELP_EXTRA_IGNORE_DIRS, HELP_EXTRA_MODULES)
 from deploy_lib.android import AndroidData, AndroidConfig
 from deploy_lib.android.buildozer import Buildozer
 
@@ -46,26 +46,6 @@ from deploy_lib.android.buildozer import Buildozer
         Note: This file is used by both pyside6-deploy and pyside6-android-deploy
 """
 
-HELP_EXTRA_IGNORE_DIRS = dedent("""
-                                Comma separated directory names inside the project dir. These
-                                directories will be skipped when searching for python files
-                                relevant to the project.
-
-                                Example usage: --extra-ignore-dirs=doc,translations
-                                """)
-
-HELP_EXTRA_MODULES = dedent("""
-                            Comma separated list of Qt modules to be added to the application,
-                            in case they are not found automatically.
-
-                            This occurs when you have 'import PySide6' in your code instead
-                            'from PySide6 import <module>'. The module name is specified
-                            with either omitting the prefix of Qt or with it.
-
-                            Example usage 1: --extra-modules=Network,Svg
-                            Example usage 2: --extra-modules=QtNetwork,QtSvg
-                            """)
-
 
 def main(name: str = None, pyside_wheel: Path = None, shiboken_wheel: Path = None,
          ndk_path: Path = None, sdk_path: Path = None, config_file: Path = None, init: bool = False,
@@ -96,7 +76,7 @@ def main(name: str = None, pyside_wheel: Path = None, shiboken_wheel: Path = Non
     android_data = AndroidData(wheel_pyside=pyside_wheel, wheel_shiboken=shiboken_wheel,
                                ndk_path=ndk_path, sdk_path=sdk_path)
 
-    python = setup_python(dry_run=dry_run, force=force, init=init)
+    python = PythonExecutable(dry_run=dry_run, init=init, force=force)
 
     config_file_exists = config_file and Path(config_file).exists()
 
@@ -117,19 +97,19 @@ def main(name: str = None, pyside_wheel: Path = None, shiboken_wheel: Path = Non
 
     cleanup(config=config, is_android=True)
 
-    install_python_dependencies(config=config, python=python, init=init,
-                                packages="android_packages", is_android=True)
+    python.install_dependencies(config=config, packages="android_packages", is_android=True)
 
     # set application name
     if name:
         config.title = name
 
     try:
-        config.modules += extra_modules
+        config.modules += list(set(extra_modules).difference(set(config.modules)))
 
         # this cannot be done when config file is initialized because cleanup() removes it
         # so this can only be done after the cleanup()
         config.find_and_set_jars_dir()
+        config.verify_and_set_recipe_dir()
 
         # TODO: include qml files from pysidedeploy.spec rather than from extensions
         # buildozer currently includes all the files with .qml extension
index f976cb5a625659077295c434a5bf966e007570fa..bc6347243d0b254c1da8a7c3955d5c025985681d 100644 (file)
@@ -4,6 +4,6 @@
               "deploy_lib/android/recipes/PySide6/__init__.tmpl.py",
               "deploy_lib/android/recipes/shiboken6/__init__.tmpl.py",
               "deploy_lib/android/__init__.py", "deploy_lib/android/android_helper.py",
-              "deploy_lib/android/buildozer.py"
+              "deploy_lib/android/buildozer.py", "deploy_lib/dependency_util.py"
               ]
 }
index eafbdbbeb1855d3ae16598f0ae94dc5ec5723016..4b6260ccee684379621d5601bbeafa5ebbbde777 100644 (file)
@@ -16,11 +16,8 @@ macro(create_and_install_qt_javabindings)
     set(android_main_srcs "${QT6_INSTALL_PREFIX}/src/android/java/src/org/qtproject/qt/android/bindings")
     set(java_sources
         ${android_main_srcs}/QtActivity.java
-        ${android_main_srcs}/QtActivityLoader.java
         ${android_main_srcs}/QtApplication.java
-        ${android_main_srcs}/QtLoader.java
         ${android_main_srcs}/QtService.java
-        ${android_main_srcs}/QtServiceLoader.java
     )
     # set android.jar from the sdk, for compiling the java files into .jar
     set(sdk_jar_location "${ANDROID_SDK_ROOT}/platforms/${ANDROID_PLATFORM}/android.jar")
index 0aea807a8472ae2bafabe78929c8ba5155654646..aa03d13d07389deb996c9b8136e034db59fbb166 100644 (file)
@@ -34,14 +34,25 @@ import traceback
 from pathlib import Path
 from textwrap import dedent
 
-from deploy_lib import (MAJOR_VERSION, Config, cleanup, config_option_exists,
-                        finalize, create_config_file, install_python_dependencies,
-                        setup_python)
+from deploy_lib import (MAJOR_VERSION, DesktopConfig, cleanup, config_option_exists,
+                        finalize, create_config_file, PythonExecutable, Nuitka,
+                        HELP_EXTRA_MODULES, HELP_EXTRA_IGNORE_DIRS)
+
+
+TOOL_DESCRIPTION = dedent(f"""
+                          This tool deploys PySide{MAJOR_VERSION} to desktop (Windows, Linux,
+                          macOS) platforms. The following types of executables are produced as per
+                          the platform:
+
+                          Windows = .exe
+                          macOS = .app
+                          Linux = .bin
+                          """)
 
 
 def main(main_file: Path = None, name: str = None, config_file: Path = None, init: bool = False,
          loglevel=logging.WARNING, dry_run: bool = False, keep_deployment_files: bool = False,
-         force: bool = False):
+         force: bool = False, extra_ignore_dirs: str = None, extra_modules_grouped: str = None):
 
     logging.basicConfig(level=loglevel)
     if config_file and not config_file.exists() and not main_file.exists():
@@ -57,7 +68,19 @@ def main(main_file: Path = None, name: str = None, config_file: Path = None, ini
     config = None
     logging.info("[DEPLOY] Start")
 
-    python = setup_python(dry_run=dry_run, force=force, init=init)
+    if extra_ignore_dirs:
+        extra_ignore_dirs = extra_ignore_dirs.split(",")
+
+    extra_modules = []
+    if extra_modules_grouped:
+        tmp_extra_modules = extra_modules_grouped.split(",")
+        for extra_module in tmp_extra_modules:
+            if extra_module.startswith("Qt"):
+                extra_modules.append(extra_module[2:])
+            else:
+                extra_modules.append(extra_module)
+
+    python = PythonExecutable(dry_run=dry_run, init=init, force=force)
     config_file_exists = config_file and Path(config_file).exists()
 
     if config_file_exists:
@@ -66,8 +89,9 @@ def main(main_file: Path = None, name: str = None, config_file: Path = None, ini
         config_file = create_config_file(dry_run=dry_run, config_file=config_file,
                                          main_file=main_file)
 
-    config = Config(config_file=config_file, source_file=main_file, python_exe=python.exe,
-                    dry_run=dry_run, existing_config_file=config_file_exists)
+    config = DesktopConfig(config_file=config_file, source_file=main_file, python_exe=python.exe,
+                           dry_run=dry_run, existing_config_file=config_file_exists,
+                           extra_ignore_dirs=extra_ignore_dirs)
 
     # set application name
     if name:
@@ -75,20 +99,24 @@ def main(main_file: Path = None, name: str = None, config_file: Path = None, ini
 
     cleanup(config=config)
 
-    install_python_dependencies(config=config, python=python, init=init,
-                                packages="packages")
+    python.install_dependencies(config=config, packages="packages")
 
     # required by Nuitka for pyenv Python
     add_arg = " --static-libpython=no"
     if python.is_pyenv_python() and add_arg not in config.extra_args:
         config.extra_args += add_arg
 
+    config.modules += list(set(extra_modules).difference(set(config.modules)))
+
     # writing config file
     # in the case of --dry-run, we use default.spec as reference. Do not save the changes
     # for --dry-run
     if not dry_run:
         config.update_config()
 
+    if config.qml_files:
+        logging.info(f"[DEPLOY] Included QML files: {config.qml_files}")
+
     if init:
         # config file created above. Exiting.
         logging.info(f"[DEPLOY]: Config file {config.config_file} created")
@@ -99,9 +127,15 @@ def main(main_file: Path = None, name: str = None, config_file: Path = None, ini
         if not dry_run:
             logging.info("[DEPLOY] Deploying application")
 
-        command_str = python.create_executable(source_file=config.source_file,
+        nuitka = Nuitka(nuitka=[python.exe, "-m", "nuitka"])
+        command_str = nuitka.create_executable(source_file=config.source_file,
                                                extra_args=config.extra_args,
-                                               config=config)
+                                               qml_files=config.qml_files,
+                                               qt_plugins=config.qt_plugins,
+                                               excluded_qml_plugins=config.excluded_qml_plugins,
+                                               icon=config.icon,
+                                               dry_run=dry_run,
+                                               permissions=config.permissions)
     except Exception:
         print(f"[DEPLOY] Exception occurred: {traceback.format_exc()}")
     finally:
@@ -115,11 +149,7 @@ def main(main_file: Path = None, name: str = None, config_file: Path = None, ini
 
 
 if __name__ == "__main__":
-    parser = argparse.ArgumentParser(
-        description=(f"This tool deploys PySide{MAJOR_VERSION} to desktop (Windows, Linux, macOS)"
-                     "platforms"),
-        formatter_class=argparse.RawTextHelpFormatter,
-    )
+    parser = argparse.ArgumentParser(description=TOOL_DESCRIPTION)
 
     parser.add_argument("-c", "--config-file", type=lambda p: Path(p).absolute(),
                         default=(Path.cwd() / "pysidedeploy.spec"),
@@ -148,7 +178,11 @@ if __name__ == "__main__":
 
     parser.add_argument("--name", type=str, help="Application name")
 
+    parser.add_argument("--extra-ignore-dirs", type=str, help=HELP_EXTRA_IGNORE_DIRS)
+
+    parser.add_argument("--extra-modules", type=str, help=HELP_EXTRA_MODULES)
+
     args = parser.parse_args()
 
     main(args.main_file, args.name, args.config_file, args.init, args.loglevel, args.dry_run,
-         args.keep_deployment_files, args.force)
+         args.keep_deployment_files, args.force, args.extra_ignore_dirs, args.extra_modules)
index eef1668c5edf0279fbc5b56673afd1e2a8de43e5..0e6ca8251dfea507674adb9ee7f2b9c795f72c4f 100644 (file)
@@ -2,6 +2,7 @@
     "files": ["deploy.py", "deploy_lib/__init__.py", "deploy_lib/commands.py", "deploy_lib/config.py",
               "deploy_lib/default.spec", "deploy_lib/nuitka_helper.py", "deploy_lib/pyside_icon.ico",
               "deploy_lib/pyside_icon.icns","deploy_lib/pyside_icon.jpg",
-              "deploy_lib/python_helper.py", "deploy_lib/deploy_util.py"
+              "deploy_lib/python_helper.py", "deploy_lib/deploy_util.py",
+              "deploy_lib/dependency_util.py"
               ]
 }
index 8c5d8b4ef48280d02fc05a301bdac043872d6f87..a40d0838b4406c0915b022a025688652a20f4d77 100644 (file)
@@ -2,6 +2,7 @@
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 import sys
 from pathlib import Path
+from textwrap import dedent
 
 MAJOR_VERSION = 6
 
@@ -10,16 +11,49 @@ if sys.platform == "win32":
     EXE_FORMAT = ".exe"
 elif sys.platform == "darwin":
     IMAGE_FORMAT = ".icns"
-    EXE_FORMAT = ".bin"
+    EXE_FORMAT = ".app"
 else:
     IMAGE_FORMAT = ".jpg"
     EXE_FORMAT = ".bin"
 
 DEFAULT_APP_ICON = str((Path(__file__).parent / f"pyside_icon{IMAGE_FORMAT}").resolve())
+IMPORT_WARNING_PYSIDE = (f"[DEPLOY] Found 'import PySide6' in file {0}"
+                         ". Use 'from PySide6 import <module>' or pass the module"
+                         " needed using --extra-modules command line argument")
+HELP_EXTRA_IGNORE_DIRS = dedent("""
+                                Comma-separated directory names inside the project dir. These
+                                directories will be skipped when searching for Python files
+                                relevant to the project.
+
+                                Example usage: --extra-ignore-dirs=doc,translations
+                                """)
+
+HELP_EXTRA_MODULES = dedent("""
+                            Comma-separated list of Qt modules to be added to the application,
+                            in case they are not found automatically.
+
+                            This occurs when you have 'import PySide6' in your code instead
+                            'from PySide6 import <module>'. The module name is specified
+                            by either omitting the prefix of Qt or including it.
+
+                            Example usage 1: --extra-modules=Network,Svg
+                            Example usage 2: --extra-modules=QtNetwork,QtSvg
+                            """)
+
+
+def get_all_pyside_modules():
+    """
+    Returns all the modules installed with PySide6
+    """
+    import PySide6
+    # They all start with `Qt` as the prefix. Removing this prefix and getting the actual
+    # module name
+    return [module[2:] for module in PySide6.__all__]
+
 
-from .commands import run_command
+from .commands import run_command, run_qmlimportscanner
+from .dependency_util import find_pyside_modules, find_permission_categories, QtDependencyReader
 from .nuitka_helper import Nuitka
-from .python_helper import PythonExecutable, find_pyside_modules
-from .config import BaseConfig, Config
-from .deploy_util import (cleanup, finalize, create_config_file, setup_python,
-                          install_python_dependencies, config_option_exists)
+from .config import BaseConfig, Config, DesktopConfig
+from .python_helper import PythonExecutable
+from .deploy_util import cleanup, finalize, create_config_file, config_option_exists
index 59cd510c58ccbd4508198867d774402f5e253b93..c3027762c541f314c4dba3bacd791e9599a49917 100644 (file)
@@ -1,7 +1,16 @@
 # Copyright (C) 2023 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
-from .android_helper import (create_recipe, extract_and_copy_jar,
-                             get_wheel_android_arch, AndroidData, get_llvm_readobj,
-                             find_lib_dependencies, find_qtlibs_in_wheel)
+# maps instruction set to Android platform names
+platform_map = {"aarch64": "arm64-v8a",
+                "armv7a": "armeabi-v7a",
+                "i686": "x86",
+                "x86_64": "x86_64",
+                "arm64-v8a": "arm64-v8a",
+                "armeabi-v7a": "armeabi-v7a",
+                "x86": "x86"}
+
+from .android_helper import (create_recipe, extract_and_copy_jar, get_wheel_android_arch,
+                             AndroidData, get_llvm_readobj, find_lib_dependencies,
+                             find_qtlibs_in_wheel)
 from .android_config import AndroidConfig
index 442672a234c9d4ddca70477bfbb61b950ee60ac5..ad818c2ff0787739d5d725a1bb828ff291f58be5 100644 (file)
@@ -1,14 +1,20 @@
 # Copyright (C) 2023 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+import re
+import tempfile
 import logging
+import zipfile
+import xml.etree.ElementTree as ET
 
 from typing import List
 from pathlib import Path
+from pkginfo import Wheel
 
-from . import extract_and_copy_jar, get_wheel_android_arch
-from .. import Config, find_pyside_modules
+from . import (extract_and_copy_jar, get_wheel_android_arch, find_lib_dependencies,
+               get_llvm_readobj, find_qtlibs_in_wheel, platform_map, create_recipe)
+from .. import (Config, find_pyside_modules, get_all_pyside_modules, MAJOR_VERSION)
 
-ANDROID_NDK_VERSION = "25c"
+ANDROID_NDK_VERSION = "26b"
 ANDROID_DEPLOY_CACHE = Path.home() / ".pyside6_android_deploy"
 
 
@@ -86,28 +92,52 @@ class AndroidConfig(Config):
         if jars_dir_temp and Path(jars_dir_temp).resolve().exists():
             self.jars_dir = Path(jars_dir_temp).resolve()
 
-        self._modules = []
-        if self.get_value("buildozer", "modules"):
-            self.modules = self.get_value("buildozer", "modules").split(",")
-        else:
-            self._find_and_set_pysidemodules()
-            self._find_and_set_qtquick_modules()
-
         self._arch = None
         if self.get_value("buildozer", "arch"):
             self.arch = self.get_value("buildozer", "arch")
         else:
             self._find_and_set_arch()
 
+        # maps to correct platform name incase the instruction set was specified
+        self._arch = platform_map[self.arch]
+
+        self._mode = self.get_value("buildozer", "mode")
+
+        self.qt_libs_path: zipfile.Path = find_qtlibs_in_wheel(wheel_pyside=self.wheel_pyside)
+        logging.info(f"[DEPLOY] Qt libs path inside wheel: {str(self.qt_libs_path)}")
+
+        if self.get_value("qt", "modules"):
+            self.modules = self.get_value("qt", "modules").split(",")
+        else:
+            self._find_and_set_pysidemodules()
+            self._find_and_set_qtquick_modules()
+            self.modules += self._find_dependent_qt_modules()
+            # remove duplicates
+            self.modules = list(set(self.modules))
+
+        # gets the xml dependency files from Qt installation path
+        self._dependency_files = []
+        self._find_and_set_dependency_files()
+
+        dependent_plugins = []
         self._local_libs = []
         if self.get_value("buildozer", "local_libs"):
-            self.local_libs = self.get_value("buildozer", "local_libs").split(",")
+            self._local_libs = self.get_value("buildozer", "local_libs").split(",")
+        else:
+            # the local_libs can also store dependent plugins
+            local_libs, dependent_plugins = self._find_local_libs()
+            self.local_libs = list(set(local_libs))
 
         self._qt_plugins = []
         if self.get_value("android", "plugins"):
             self._qt_plugins = self.get_value("android", "plugins").split(",")
+        elif dependent_plugins:
+            self._find_plugin_dependencies(dependent_plugins)
+            self.qt_plugins = list(set(dependent_plugins))
 
-        self._mode = self.get_value("buildozer", "mode")
+        recipe_dir_temp = self.get_value("buildozer", "recipe_dir")
+        if recipe_dir_temp:
+            self.recipe_dir = Path(recipe_dir_temp)
 
     @property
     def qt_plugins(self):
@@ -158,7 +188,7 @@ class AndroidConfig(Config):
     @modules.setter
     def modules(self, modules):
         self._modules = modules
-        self.set_value("buildozer", "modules", ",".join(modules))
+        self.set_value("qt", "modules", ",".join(modules))
 
     @property
     def local_libs(self):
@@ -218,6 +248,14 @@ class AndroidConfig(Config):
         if self._wheel_shiboken:
             self.set_value("android", "wheel_shiboken", str(self._wheel_shiboken))
 
+    @property
+    def dependency_files(self):
+        return self._dependency_files
+
+    @dependency_files.setter
+    def dependency_files(self, dependency_files):
+        self._dependency_files = dependency_files
+
     def _find_and_set_pysidemodules(self):
         self.modules = find_pyside_modules(project_dir=self.project_dir,
                                            extra_ignore_dirs=self.extra_ignore_dirs,
@@ -242,15 +280,167 @@ class AndroidConfig(Config):
             raise RuntimeError("[DEPLOY] PySide wheel corrupted. Wheel name should end with"
                                "platform name")
 
-    def _find_and_set_qtquick_modules(self):
-        """Identify if QtQuick is used in QML files and add them as dependency
+    def _find_dependent_qt_modules(self):
         """
-        extra_modules = []
-
-        if "QtQuick" in self.qml_modules:
-            extra_modules.append("Quick")
-
-        if "QtQuick.Controls" in self.qml_modules:
-            extra_modules.append("QuickControls2")
-
-        self.modules += extra_modules
+        Given pysidedeploy_config.modules, find all the other dependent Qt modules. This is
+        done by using llvm-readobj (readelf) to find the dependent libraries from the module
+        library.
+        """
+        dependent_modules = set()
+        all_dependencies = set()
+        lib_pattern = re.compile(f"libQt6(?P<mod_name>.*)_{self.arch}")
+
+        llvm_readobj = get_llvm_readobj(self.ndk_path)
+        if not llvm_readobj.exists():
+            raise FileNotFoundError(f"[DEPLOY] {llvm_readobj} does not exist."
+                                    "Finding Qt dependencies failed")
+
+        archive = zipfile.ZipFile(self.wheel_pyside)
+        lib_path_suffix = Path(str(self.qt_libs_path)).relative_to(self.wheel_pyside)
+
+        with tempfile.TemporaryDirectory() as tmpdir:
+            archive.extractall(tmpdir)
+            qt_libs_tmpdir = Path(tmpdir) / lib_path_suffix
+            # find the lib folder where Qt libraries are stored
+            for module_name in sorted(self.modules):
+                qt_module_path = qt_libs_tmpdir / f"libQt6{module_name}_{self.arch}.so"
+                if not qt_module_path.exists():
+                    raise FileNotFoundError(f"[DEPLOY] libQt6{module_name}_{self.arch}.so not found"
+                                            " inside the wheel")
+                find_lib_dependencies(llvm_readobj=llvm_readobj, lib_path=qt_module_path,
+                                      dry_run=self.dry_run,
+                                      used_dependencies=all_dependencies)
+
+        for dependency in all_dependencies:
+            match = lib_pattern.search(dependency)
+            if match:
+                module = match.group("mod_name")
+                if module not in self.modules:
+                    dependent_modules.add(module)
+
+        # check if the PySide6 binary for the Qt module actually exists
+        # eg: libQt6QmlModels.so exists and it includes QML types. Hence, it makes no
+        dependent_modules = [module for module in dependent_modules if module in
+                             get_all_pyside_modules()]
+        dependent_modules_str = ",".join(dependent_modules)
+        logging.info("[DEPLOY] The following extra dependencies were found:"
+                     f" {dependent_modules_str}")
+
+        return dependent_modules
+
+    def _find_and_set_dependency_files(self) -> List[zipfile.Path]:
+        """
+        Based on `modules`, returns the Qt6{module}_{arch}-android-dependencies.xml file, which
+        contains the various dependencies of the module, like permissions, plugins etc
+        """
+        needed_dependency_files = [(f"Qt{MAJOR_VERSION}{module}_{self.arch}"
+                                    "-android-dependencies.xml") for module in self.modules]
+
+        for dependency_file_name in needed_dependency_files:
+            dependency_file = self.qt_libs_path / dependency_file_name
+            if dependency_file.exists():
+                self._dependency_files.append(dependency_file)
+
+        logging.info("[DEPLOY] The following dependency files were found: "
+                     f"{*self._dependency_files,}")
+
+    def _find_local_libs(self):
+        local_libs = set()
+        plugins = set()
+        lib_pattern = re.compile(f"lib(?P<lib_name>.*)_{self.arch}")
+        for dependency_file in self._dependency_files:
+            xml_content = dependency_file.read_text()
+            root = ET.fromstring(xml_content)
+            for local_lib in root.iter("lib"):
+
+                if 'file' not in local_lib.attrib:
+                    if 'name' not in local_lib.attrib:
+                        logging.warning("[DEPLOY] Invalid android dependency file"
+                                        f" {str(dependency_file)}")
+                    continue
+
+                file = local_lib.attrib['file']
+                if file.endswith(".so"):
+                    # file_name starts with lib and ends with the platform name
+                    # eg: lib<lib_name>_x86_64.so
+                    file_name = Path(file).stem
+
+                    # we only need lib_name, because lib and arch gets re-added by
+                    # python-for-android
+                    match = lib_pattern.search(file_name)
+                    if match:
+                        lib_name = match.group("lib_name")
+                        local_libs.add(lib_name)
+                        if lib_name.startswith("plugins"):
+                            plugin_name = lib_name.split('plugins_', 1)[1]
+                            plugins.add(plugin_name)
+
+        return list(local_libs), list(plugins)
+
+    def _find_plugin_dependencies(self, dependent_plugins: List[str]):
+        # The `bundled` element in the dependency xml files points to the folder where
+        # additional dependencies for the application exists. Inspecting the depenency files
+        # in android, this always points to the specific Qt plugin dependency folder.
+        # eg: for application using Qt Multimedia, this looks like:
+        # <bundled file="./plugins/multimedia" />
+        # The code recusively checks all these dependent folders and adds the necessary plugins
+        # as dependencies
+        lib_pattern = re.compile(f"libplugins_(?P<plugin_name>.*)_{self.arch}.so")
+        for dependency_file in self._dependency_files:
+            xml_content = dependency_file.read_text()
+            root = ET.fromstring(xml_content)
+            for bundled_element in root.iter("bundled"):
+                # the attribute 'file' can be misleading, but it always points to the plugin
+                # folder on inspecting the dependency files
+                if 'file' not in bundled_element.attrib:
+                    logging.warning("[DEPLOY] Invalid Android dependency file"
+                                    f" {str(dependency_file)}")
+                    continue
+
+                # from "./plugins/multimedia" to absolute path in wheel
+                plugin_module_folder = bundled_element.attrib['file']
+                # they all should start with `./plugins`
+                if plugin_module_folder.startswith("./plugins"):
+                    plugin_module_folder = plugin_module_folder.partition("./plugins/")[2]
+                else:
+                    continue
+
+                absolute_plugin_module_folder = (self.qt_libs_path.parent / "plugins"
+                                                 / plugin_module_folder)
+
+                if not absolute_plugin_module_folder.is_dir():
+                    logging.warning(f"[DEPLOY] Qt plugin folder '{plugin_module_folder}' does not"
+                                    " exist or is not a directory for this Android platform")
+                    continue
+
+                for plugin in absolute_plugin_module_folder.iterdir():
+                    plugin_name = plugin.name
+                    if plugin_name.endswith(".so") and plugin_name.startswith("libplugins"):
+                        # we only need part of plugin_name, because `lib` prefix and `arch` suffix
+                        # gets re-added by python-for-android
+                        match = lib_pattern.search(plugin_name)
+                        if match:
+                            plugin_infix_name = match.group("plugin_name")
+                            if plugin_infix_name not in dependent_plugins:
+                                dependent_plugins.append(plugin_infix_name)
+
+    def verify_and_set_recipe_dir(self):
+        # create recipes
+        # https://python-for-android.readthedocs.io/en/latest/recipes/
+        # These recipes are manually added through buildozer.spec file to be used by
+        # python_for_android while building the distribution
+
+        if not self.recipes_exist() and not self.dry_run:
+            logging.info("[DEPLOY] Creating p4a recipes for PySide6 and shiboken6")
+            version = Wheel(self.wheel_pyside).version
+            create_recipe(version=version, component=f"PySide{MAJOR_VERSION}",
+                          wheel_path=self.wheel_pyside,
+                          generated_files_path=self.generated_files_path,
+                          qt_modules=self.modules,
+                          local_libs=self.local_libs,
+                          plugins=self.qt_plugins)
+            create_recipe(version=version, component=f"shiboken{MAJOR_VERSION}",
+                          wheel_path=self.wheel_shiboken,
+                          generated_files_path=self.generated_files_path)
+            self.recipe_dir = ((self.generated_files_path
+                                / "recipes").resolve())
index 2303436476d74037f0ea9481179413436cc6022a..7d2f5d57523d556e4b732c83f0ea0fa92348242a 100644 (file)
@@ -102,8 +102,15 @@ def find_lib_dependencies(llvm_readobj: Path, lib_path: Path, used_dependencies:
     if lib_path.name in used_dependencies:
         return
 
+    used_dependencies.add(lib_path.name)
+
     command = [str(llvm_readobj), "--needed-libs", str(lib_path)]
-    _, output = run_command(command=command, dry_run=dry_run, fetch_output=True)
+
+    # even if dry_run is given, we need to run the actual command to see all the dependencies
+    # for which llvm-readelf is run.
+    if dry_run:
+        _, output = run_command(command=command, dry_run=dry_run, fetch_output=True)
+    _, output = run_command(command=command, dry_run=False, fetch_output=True)
 
     dependencies = set()
     neededlibraries_found = False
index 3c188b1c01ee3eda25606ad62e1c5dcfcb6e13f4..0c314c3563a00eb9525cfddc369c393793b61a3b 100644 (file)
@@ -3,27 +3,17 @@
 
 import sys
 import logging
-import re
-import tempfile
 import xml.etree.ElementTree as ET
 import zipfile
-import PySide6
 from pathlib import Path
 from typing import List
 
-from pkginfo import Wheel
-
-from .. import MAJOR_VERSION, BaseConfig, Config, run_command
-from . import (create_recipe, find_lib_dependencies, find_qtlibs_in_wheel,
-               get_llvm_readobj)
-
-# They all start with `Qt` as the prefix. Removing this prefix and getting the actual
-# module name
-ALL_PYSIDE_MODULES = [module[2:] for module in PySide6.__all__]
+from . import AndroidConfig
+from .. import BaseConfig, run_command
 
 
 class BuildozerConfig(BaseConfig):
-    def __init__(self, buildozer_spec_file: Path, pysidedeploy_config: Config):
+    def __init__(self, buildozer_spec_file: Path, pysidedeploy_config: AndroidConfig):
         super().__init__(buildozer_spec_file, comment_prefixes="#")
         self.set_value("app", "title", pysidedeploy_config.title)
         self.set_value("app", "package.name", pysidedeploy_config.title)
@@ -43,70 +33,33 @@ class BuildozerConfig(BaseConfig):
         if pysidedeploy_config.sdk_path:
             self.set_value("app", "android.sdk_path", str(pysidedeploy_config.sdk_path))
 
-        platform_map = {"aarch64": "arm64-v8a",
-                        "armv7a": "armeabi-v7a",
-                        "i686": "x86",
-                        "x86_64": "x86_64"}
-        self.arch = platform_map[pysidedeploy_config.arch]
-        self.set_value("app", "android.archs", self.arch)
+        self.set_value("app", "android.archs", pysidedeploy_config.arch)
 
         # p4a changes
         self.set_value("app", "p4a.bootstrap", "qt")
-
-        self.qt_libs_path: zipfile.Path = (
-            find_qtlibs_in_wheel(wheel_pyside=pysidedeploy_config.wheel_pyside))
-        logging.info(f"[DEPLOY] Found Qt libs path inside wheel: {str(self.qt_libs_path)}")
-
-        extra_modules = self.__find_dependent_qt_modules(pysidedeploy_config)
-        logging.info(f"[DEPLOY] Other dependent modules to be added: {extra_modules}")
-        pysidedeploy_config.modules = pysidedeploy_config.modules + extra_modules
-        modules = ",".join(pysidedeploy_config.modules)
-
-        # gets the xml dependency files from Qt installation path
-        dependency_files = self.__get_dependency_files(modules=pysidedeploy_config.modules,
-                                                       arch=self.arch)
-
-        dependent_plugins = []
-        # the local_libs can also store dependent plugins
-        local_libs, dependent_plugins = self.__find_local_libs(dependency_files)
-        pysidedeploy_config.local_libs += local_libs
-
-        self.__find_plugin_dependencies(dependency_files, dependent_plugins)
-        pysidedeploy_config.qt_plugins += dependent_plugins
-
-        local_libs = ",".join(pysidedeploy_config.local_libs)
-
-        # create recipes
-        # https://python-for-android.readthedocs.io/en/latest/recipes/
-        # These recipes are manually added through buildozer.spec file to be used by
-        # python_for_android while building the distribution
-        if not pysidedeploy_config.recipes_exist() and not pysidedeploy_config.dry_run:
-            logging.info("[DEPLOY] Creating p4a recipes for PySide6 and shiboken6")
-            version = Wheel(pysidedeploy_config.wheel_pyside).version
-            create_recipe(version=version, component=f"PySide{MAJOR_VERSION}",
-                          wheel_path=pysidedeploy_config.wheel_pyside,
-                          generated_files_path=pysidedeploy_config.generated_files_path,
-                          qt_modules=pysidedeploy_config.modules,
-                          local_libs=pysidedeploy_config.local_libs,
-                          plugins=pysidedeploy_config.qt_plugins)
-            create_recipe(version=version, component=f"shiboken{MAJOR_VERSION}",
-                          wheel_path=pysidedeploy_config.wheel_shiboken,
-                          generated_files_path=pysidedeploy_config.generated_files_path)
-            pysidedeploy_config.recipe_dir = ((pysidedeploy_config.generated_files_path
-                                              / "recipes").resolve())
         self.set_value('app', "p4a.local_recipes", str(pysidedeploy_config.recipe_dir))
 
+        # add p4a branch
+        # by default the master branch is used
+        # https://github.com/kivy/python-for-android/commit/b92522fab879dbfc0028966ca3c59ef46ab7767d
+        # has not been merged to master yet. So, we use the develop branch for now
+        # TODO: remove this once the above commit is merged to master
+        self.set_value("app", "p4a.branch", "develop")
+
         # add permissions
-        permissions = self.__find_permissions(dependency_files)
+        permissions = self.__find_permissions(pysidedeploy_config.dependency_files)
         permissions = ", ".join(permissions)
         self.set_value("app", "android.permissions", permissions)
 
         # add jars and initClasses for the jars
-        jars, init_classes = self.__find_jars(dependency_files, pysidedeploy_config.jars_dir)
+        jars, init_classes = self.__find_jars(pysidedeploy_config.dependency_files,
+                                              pysidedeploy_config.jars_dir)
         self.set_value("app", "android.add_jars", ",".join(jars))
-        init_classes = ",".join(init_classes)
 
         # extra arguments specific to Qt
+        modules = ",".join(pysidedeploy_config.modules)
+        local_libs = ",".join(pysidedeploy_config.local_libs)
+        init_classes = ",".join(init_classes)
         extra_args = (f"--qt-libs={modules} --load-local-libs={local_libs}"
                       f" --init-classes={init_classes}")
         self.set_value("app", "p4a.extra_args", extra_args)
@@ -123,25 +76,6 @@ class BuildozerConfig(BaseConfig):
 
         self.update_config()
 
-    def __get_dependency_files(self, modules: List[str], arch: str) -> List[zipfile.Path]:
-        """
-        Based on pysidedeploy_config.modules, returns the
-        Qt6{module}_{arch}-android-dependencies.xml file, which contains the various
-        dependencies of the module, like permissions, plugins etc
-        """
-        dependency_files = []
-        needed_dependency_files = [(f"Qt{MAJOR_VERSION}{module}_{arch}"
-                                    "-android-dependencies.xml") for module in modules]
-
-        for dependency_file_name in needed_dependency_files:
-            dependency_file = self.qt_libs_path / dependency_file_name
-            if dependency_file.exists():
-                dependency_files.append(dependency_file)
-
-        logging.info(f"[DEPLOY] The following dependency files were found: {*dependency_files,}")
-
-        return dependency_files
-
     def __find_permissions(self, dependency_files: List[zipfile.Path]):
         permissions = set()
         for dependency_file in dependency_files:
@@ -186,145 +120,12 @@ class BuildozerConfig(BaseConfig):
 
         return jars, init_classes
 
-    def __find_local_libs(self, dependency_files: List[zipfile.Path]):
-        local_libs = set()
-        plugins = set()
-        lib_pattern = re.compile(f"lib(?P<lib_name>.*)_{self.arch}")
-        for dependency_file in dependency_files:
-            xml_content = dependency_file.read_text()
-            root = ET.fromstring(xml_content)
-            for local_lib in root.iter("lib"):
-
-                if 'file' not in local_lib.attrib:
-                    if 'name' not in local_lib.attrib:
-                        logging.warning("[DEPLOY] Invalid android dependency file"
-                                        f" {str(dependency_file)}")
-                    continue
-
-                file = local_lib.attrib['file']
-                if file.endswith(".so"):
-                    # file_name starts with lib and ends with the platform name
-                    # eg: lib<lib_name>_x86_64.so
-                    file_name = Path(file).stem
-
-                    if file_name.startswith("libplugins_platforms_qtforandroid"):
-                        # the platform library is a requisite and is already added from the
-                        # configuration file
-                        continue
-
-                    # we only need lib_name, because lib and arch gets re-added by
-                    # python-for-android
-                    match = lib_pattern.search(file_name)
-                    if match:
-                        lib_name = match.group("lib_name")
-                        local_libs.add(lib_name)
-                        if lib_name.startswith("plugins"):
-                            plugin_name = lib_name.split('plugins_', 1)[1]
-                            plugins.add(plugin_name)
-
-        return list(local_libs), list(plugins)
-
-    def __find_plugin_dependencies(self, dependency_files: List[zipfile.Path],
-                                   dependent_plugins: List[str]):
-        # The `bundled` element in the dependency xml files points to the folder where
-        # additional dependencies for the application exists. Inspecting the depenency files
-        # in android, this always points to the specific Qt plugin dependency folder.
-        # eg: for application using Qt Multimedia, this looks like:
-        # <bundled file="./plugins/multimedia" />
-        # The code recusively checks all these dependent folders and adds the necessary plugins
-        # as dependencies
-        lib_pattern = re.compile(f"libplugins_(?P<plugin_name>.*)_{self.arch}.so")
-        for dependency_file in dependency_files:
-            xml_content = dependency_file.read_text()
-            root = ET.fromstring(xml_content)
-            for bundled_element in root.iter("bundled"):
-                # the attribute 'file' can be misleading, but it always points to the plugin
-                # folder on inspecting the dependency files
-                if 'file' not in bundled_element.attrib:
-                    logging.warning("[DEPLOY] Invalid Android dependency file"
-                                    f" {str(dependency_file)}")
-                    continue
-
-                # from "./plugins/multimedia" to absolute path in wheel
-                plugin_module_folder = bundled_element.attrib['file']
-                # they all should start with `./plugins`
-                if plugin_module_folder.startswith("./plugins"):
-                    plugin_module_folder = plugin_module_folder.partition("./plugins/")[2]
-                else:
-                    continue
-
-                absolute_plugin_module_folder = (self.qt_libs_path.parent / "plugins"
-                                                 / plugin_module_folder)
-
-                if not absolute_plugin_module_folder.is_dir():
-                    logging.warning(f"[DEPLOY] Qt plugin folder '{plugin_module_folder}' does not"
-                                    " exist or is not a directory for this Android platform")
-                    continue
-
-                for plugin in absolute_plugin_module_folder.iterdir():
-                    plugin_name = plugin.name
-                    if plugin_name.endswith(".so") and plugin_name.startswith("libplugins"):
-                        # we only need part of plugin_name, because `lib` prefix and `arch` suffix
-                        # gets re-added by python-for-android
-                        match = lib_pattern.search(plugin_name)
-                        if match:
-                            plugin_infix_name = match.group("plugin_name")
-                            if plugin_infix_name not in dependent_plugins:
-                                dependent_plugins.append(plugin_infix_name)
-
-    def __find_dependent_qt_modules(self, pysidedeploy_config: Config):
-        """
-        Given pysidedeploy_config.modules, find all the other dependent Qt modules. This is
-        done by using llvm-readobj (readelf) to find the dependent libraries from the module
-        library.
-        """
-        dependent_modules = set()
-        all_dependencies = set()
-        lib_pattern = re.compile(f"libQt6(?P<mod_name>.*)_{self.arch}")
-
-        llvm_readobj = get_llvm_readobj(pysidedeploy_config.ndk_path)
-        if not llvm_readobj.exists():
-            raise FileNotFoundError(f"[DEPLOY] {llvm_readobj} does not exist."
-                                    "Finding Qt dependencies failed")
-
-        archive = zipfile.ZipFile(pysidedeploy_config.wheel_pyside)
-        lib_path_suffix = Path(str(self.qt_libs_path)).relative_to(pysidedeploy_config.wheel_pyside)
-
-        with tempfile.TemporaryDirectory() as tmpdir:
-            archive.extractall(tmpdir)
-            qt_libs_tmpdir = Path(tmpdir) / lib_path_suffix
-            # find the lib folder where Qt libraries are stored
-            for module_name in pysidedeploy_config.modules:
-                qt_module_path = qt_libs_tmpdir / f"libQt6{module_name}_{self.arch}.so"
-                if not qt_module_path.exists():
-                    raise FileNotFoundError(f"[DEPLOY] libQt6{module_name}_{self.arch}.so not found"
-                                            " inside the wheel")
-                find_lib_dependencies(llvm_readobj=llvm_readobj, lib_path=qt_module_path,
-                                      dry_run=pysidedeploy_config.dry_run,
-                                      used_dependencies=all_dependencies)
-
-        for dependency in all_dependencies:
-            match = lib_pattern.search(dependency)
-            if match:
-                module = match.group("mod_name")
-                if module not in pysidedeploy_config.modules:
-                    dependent_modules.add(module)
-
-        # check if the PySide6 binary for the Qt module actually exists
-        # eg: libQt6QmlModels.so exists and it includes QML types. Hence, it makes no
-        dependent_modules = [module for module in dependent_modules if module in ALL_PYSIDE_MODULES]
-        dependent_modules_str = ",".join(dependent_modules)
-        logging.info("[DEPLOY] The following extra dependencies were found:"
-                     f" {dependent_modules_str}")
-
-        return list(dependent_modules)
-
 
 class Buildozer:
     dry_run = False
 
     @staticmethod
-    def initialize(pysidedeploy_config: Config):
+    def initialize(pysidedeploy_config: AndroidConfig):
         project_dir = Path(pysidedeploy_config.project_dir)
         buildozer_spec = project_dir / "buildozer.spec"
         if buildozer_spec.exists():
index 5dbaa68eba1ab922de04816ddebc9b265316fd11..d59dd92ad353dc06757d51026a98d243e2042ae2 100644 (file)
@@ -1,29 +1,42 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
+import sys
 import configparser
 import logging
 import warnings
 from configparser import ConfigParser
+from typing import List
 from pathlib import Path
 
 from project import ProjectData
-
-from .commands import run_qmlimportscanner
-from . import DEFAULT_APP_ICON
+from . import (DEFAULT_APP_ICON, find_pyside_modules, find_permission_categories,
+               QtDependencyReader, run_qmlimportscanner)
 
 # Some QML plugins like QtCore are excluded from this list as they don't contribute much to
 # executable size. Excluding them saves the extra processing of checking for them in files
 EXCLUDED_QML_PLUGINS = {"QtQuick", "QtQuick3D", "QtCharts", "QtWebEngine", "QtTest", "QtSensors"}
 
+PERMISSION_MAP = {"Bluetooth": "NSBluetoothAlwaysUsageDescription:BluetoothAccess",
+                  "Camera": "NSCameraUsageDescription:CameraAccess",
+                  "Microphone": "NSMicrophoneUsageDescription:MicrophoneAccess",
+                  "Contacts": "NSContactsUsageDescription:ContactsAccess",
+                  "Calendar": "NSCalendarsUsageDescription:CalendarAccess",
+                  # for iOS NSLocationWhenInUseUsageDescription and
+                  # NSLocationAlwaysAndWhenInUseUsageDescription are also required.
+                  "Location": "NSLocationUsageDescription:LocationAccess",
+                  }
 
-class BaseConfig:
 
+class BaseConfig:
+    """Wrapper class around any .spec file with function to read and set values for the .spec file
+    """
     def __init__(self, config_file: Path, comment_prefixes: str = "/",
                  existing_config_file: bool = False) -> None:
         self.config_file = config_file
         self.existing_config_file = existing_config_file
-        self.parser = ConfigParser(comment_prefixes=comment_prefixes, allow_no_value=True)
+        self.parser = ConfigParser(comment_prefixes=comment_prefixes, strict=False,
+                                   allow_no_value=True)
         self.parser.read(self.config_file)
 
     def update_config(self):
@@ -61,9 +74,10 @@ class Config(BaseConfig):
     """
 
     def __init__(self, config_file: Path, source_file: Path, python_exe: Path, dry_run: bool,
-                 existing_config_file: bool = False):
+                 existing_config_file: bool = False, extra_ignore_dirs: List[str] = None):
         super().__init__(config_file=config_file, existing_config_file=existing_config_file)
 
+        self.extra_ignore_dirs = extra_ignore_dirs
         self._dry_run = dry_run
         self.qml_modules = set()
         # set source_file
@@ -123,6 +137,8 @@ class Config(BaseConfig):
 
         self._generated_files_path = self.project_dir / "deployment"
 
+        self.modules = []
+
     def set_or_fetch(self, config_property_val, config_property_key, config_property_group="app"):
         """
         Write to config_file if 'config_property_key' is known without config_file
@@ -222,6 +238,15 @@ class Config(BaseConfig):
     def exe_dir(self, exe_dir: Path):
         self._exe_dir = exe_dir
 
+    @property
+    def modules(self):
+        return self._modules
+
+    @modules.setter
+    def modules(self, modules):
+        self._modules = modules
+        self.set_value("qt", "modules", ",".join(modules))
+
     def _find_and_set_qml_files(self):
         """Fetches all the qml_files in the folder and sets them if the
         field qml_files is empty in the config_dir"""
@@ -233,27 +258,17 @@ class Config(BaseConfig):
             self.qml_files = qml_files
         else:
             qml_files_temp = None
-            source_file = (
-                Path(self.get_value("app", "input_file"))
-                if self.get_value("app", "input_file")
-                else None
-            )
-            python_exe = (
-                Path(self.get_value("python", "python_path"))
-                if self.get_value("python", "python_path")
-                else None
-            )
-            if source_file and python_exe:
+            if self.source_file and self.python_path:
                 if not self.qml_files:
-                    qml_files_temp = list(source_file.parent.glob("**/*.qml"))
+                    qml_files_temp = list(self.source_file.parent.glob("**/*.qml"))
 
                 # add all QML files, excluding the ones shipped with installed PySide6
                 # The QML files shipped with PySide6 gets added if venv is used,
                 # because of recursive glob
-                if python_exe.parent.parent == source_file.parent:
+                if self.python_path.parent.parent == self.source_file.parent:
                     # python venv path is inside the main source dir
                     qml_files_temp = list(
-                        set(qml_files_temp) - set(python_exe.parent.parent.rglob("*.qml"))
+                        set(qml_files_temp) - set(self.python_path.parent.parent.rglob("*.qml"))
                     )
 
                 if len(qml_files_temp) > 500:
@@ -332,3 +347,113 @@ class Config(BaseConfig):
                 config_property_val=self.exe_dir, config_property_key="exec_directory"
             )
         ).absolute()
+
+    def _find_and_set_pysidemodules(self):
+        self.modules = find_pyside_modules(project_dir=self.project_dir,
+                                           extra_ignore_dirs=self.extra_ignore_dirs,
+                                           project_data=self.project_data)
+        logging.info("The following PySide modules were found from the Python files of "
+                     f"the project {self.modules}")
+
+    def _find_and_set_qtquick_modules(self):
+        """Identify if QtQuick is used in QML files and add them as dependency
+        """
+        extra_modules = []
+        if not self.qml_modules:
+            self.qml_modules = set(run_qmlimportscanner(qml_files=self.qml_files,
+                                                        dry_run=self.dry_run))
+
+        if "QtQuick" in self.qml_modules:
+            extra_modules.append("Quick")
+
+        if "QtQuick.Controls" in self.qml_modules:
+            extra_modules.append("QuickControls2")
+
+        self.modules += extra_modules
+
+
+class DesktopConfig(Config):
+    """Wrapper class around pysidedeploy.spec, but specific to Desktop deployment
+    """
+    def __init__(self, config_file: Path, source_file: Path, python_exe: Path, dry_run: bool,
+                 existing_config_file: bool = False, extra_ignore_dirs: List[str] = None):
+        super().__init__(config_file, source_file, python_exe, dry_run, existing_config_file,
+                         extra_ignore_dirs)
+        self.dependency_reader = QtDependencyReader(dry_run=self.dry_run)
+        if self.get_value("qt", "modules"):
+            self.modules = self.get_value("qt", "modules").split(",")
+        else:
+            self._find_and_set_pysidemodules()
+            self._find_and_set_qtquick_modules()
+            self._find_dependent_qt_modules()
+
+        self._qt_plugins = []
+        if self.get_value("qt", "plugins"):
+            self._qt_plugins = self.get_value("qt", "plugins").split(",")
+        else:
+            self.qt_plugins = self.dependency_reader.find_plugin_dependencies(self.modules,
+                                                                              python_exe)
+
+        self._permissions = []
+        if sys.platform == "darwin":
+            nuitka_macos_permissions = self.get_value("nuitka", "macos.permissions")
+            if nuitka_macos_permissions:
+                self._permissions = nuitka_macos_permissions.split(",")
+            else:
+                self._find_and_set_permissions()
+
+    @property
+    def qt_plugins(self):
+        return self._qt_plugins
+
+    @qt_plugins.setter
+    def qt_plugins(self, qt_plugins):
+        self._qt_plugins = qt_plugins
+        self.set_value("qt", "plugins", ",".join(qt_plugins))
+
+    @property
+    def permissions(self):
+        return self._permissions
+
+    @permissions.setter
+    def permissions(self, permissions):
+        self._permissions = permissions
+        self.set_value("nuitka", "macos.permissions", ",".join(permissions))
+
+    def _find_dependent_qt_modules(self):
+        """
+        Given pysidedeploy_config.modules, find all the other dependent Qt modules.
+        """
+        all_modules = set(self.modules)
+
+        if not self.dependency_reader.lib_reader:
+            warnings.warn(f"[DEPLOY] Unable to find {self.dependency_reader.lib_reader_name}. This "
+                          "tool helps to find the Qt module dependencies of the application. "
+                          "Skipping checking for dependencies.", category=RuntimeWarning)
+            return
+
+        for module_name in self.modules:
+            self.dependency_reader.find_dependencies(module=module_name, used_modules=all_modules)
+
+        self.modules = list(all_modules)
+
+    def _find_and_set_permissions(self):
+        """
+        Finds and sets the usage description string required for each permission requested by the
+        macOS application.
+        """
+        permissions = []
+        perm_categories = find_permission_categories(project_dir=self.project_dir,
+                                                     extra_ignore_dirs=self.extra_ignore_dirs,
+                                                     project_data=self.project_data)
+
+        perm_categories_str = ",".join(perm_categories)
+        logging.info(f"[DEPLOY] Usage descriptions for the {perm_categories_str} will be added to "
+                     "the Info.plist file of the macOS application bundle")
+
+        # handling permissions
+        for perm_category in perm_categories:
+            if perm_category in PERMISSION_MAP:
+                permissions.append(PERMISSION_MAP[perm_category])
+
+        self.permissions = permissions
index 7ca2edfe7986984e1d2a05a74e99460a9e951279..57f99eca13404595eed61c644a0e3e2a21920e29 100644 (file)
@@ -27,7 +27,7 @@ python_path =
 # python packages to install
 # ordered-set: increase compile time performance of nuitka packaging
 # zstandard: provides final executable size optimization
-packages = nuitka==1.8.0,ordered_set,zstandard
+packages = Nuitka==2.3.2
 
 # buildozer: for deploying Android application
 android_packages = buildozer==1.5.0,cython==0.29.33
@@ -41,6 +41,12 @@ qml_files =
 # excluded qml plugin binaries
 excluded_qml_plugins =
 
+# Qt modules used. Comma separated
+modules =
+
+# Qt plugins used by the application
+plugins =
+
 [android]
 
 # path to PySide wheel
@@ -50,10 +56,15 @@ wheel_pyside =
 wheel_shiboken =
 
 # plugins to be copied to libs folder of the packaged application. Comma separated
-plugins = platforms_qtforandroid
+plugins =
 
 [nuitka]
 
+# usage description for permissions requested by the app as found in the Info.plist file
+# of the app bundle
+# eg: NSCameraUsageDescription:CameraAccess
+macos.permissions =
+
 # (str) specify any extra nuitka arguments
 # eg: extra_args = --show-modules --follow-stdlib
 extra_args = --quiet --noinclude-qt-translations
@@ -77,12 +88,9 @@ ndk_path =
 # if empty uses default sdk path downloaded by buildozer
 sdk_path =
 
-# modules used. Comma separated
-modules =
-
 # other libraries to be loaded. Comma separated.
 # loaded at app startup
-local_libs = plugins_platforms_qtforandroid
+local_libs =
 
 # architecture of deployed platform
 # possible values: ["aarch64", "armv7a", "i686", "x86_64"]
diff --git a/sources/pyside-tools/deploy_lib/dependency_util.py b/sources/pyside-tools/deploy_lib/dependency_util.py
new file mode 100644 (file)
index 0000000..2d5b188
--- /dev/null
@@ -0,0 +1,319 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import ast
+import re
+import os
+import site
+import json
+import warnings
+import logging
+import shutil
+import sys
+from pathlib import Path
+from typing import List, Set
+from functools import lru_cache
+
+from . import IMPORT_WARNING_PYSIDE, run_command
+
+
+@lru_cache(maxsize=None)
+def get_py_files(project_dir: Path, extra_ignore_dirs: List[Path] = None, project_data=None):
+    """Finds and returns all the Python files in the project
+    """
+    py_candidates = []
+    ignore_dirs = ["__pycache__", "env", "venv", "deployment"]
+
+    if project_data:
+        py_candidates = project_data.python_files
+        ui_candidates = project_data.ui_files
+        qrc_candidates = project_data.qrc_files
+
+        def add_uic_qrc_candidates(candidates, candidate_type):
+            possible_py_candidates = [(file.parent / f"{candidate_type}_{file.stem}.py")
+                                      for file in candidates
+                                      if (file.parent / f"{candidate_type}_{file.stem}.py").exists()
+                                      ]
+
+            if len(possible_py_candidates) != len(candidates):
+                warnings.warn(f"[DEPLOY] The number of {candidate_type} files and their "
+                              "corresponding Python files don't match.",
+                              category=RuntimeWarning)
+
+            py_candidates.extend(possible_py_candidates)
+
+        if ui_candidates:
+            add_uic_qrc_candidates(ui_candidates, "ui")
+
+        if qrc_candidates:
+            add_uic_qrc_candidates(qrc_candidates, "qrc")
+
+        return py_candidates
+
+    # incase there is not .pyproject file, search all python files in project_dir, except
+    # ignore_dirs
+    if extra_ignore_dirs:
+        ignore_dirs.extend(extra_ignore_dirs)
+
+    # find relevant .py files
+    _walk = os.walk(project_dir)
+    for root, dirs, files in _walk:
+        dirs[:] = [d for d in dirs if d not in ignore_dirs and not d.startswith(".")]
+        for py_file in files:
+            if py_file.endswith(".py"):
+                py_candidates.append(Path(root) / py_file)
+
+    return py_candidates
+
+
+@lru_cache(maxsize=None)
+def get_ast(py_file: Path):
+    """Given a Python file returns the abstract syntax tree
+    """
+    contents = py_file.read_text(encoding="utf-8")
+    try:
+        tree = ast.parse(contents)
+    except SyntaxError:
+        print(f"[DEPLOY] Unable to parse {py_file}")
+    return tree
+
+
+def find_permission_categories(project_dir: Path, extra_ignore_dirs: List[Path] = None,
+                               project_data=None):
+    """Given the project directory, finds all the permission categories required by the
+    project. eg: Camera, Bluetooth, Contacts etc.
+
+    Note: This function is only relevant for mac0S deployment.
+    """
+    all_perm_categories = set()
+    mod_pattern = re.compile("Q(?P<mod_name>.*)Permission")
+
+    def pyside_permission_imports(py_file: Path):
+        perm_categories = []
+        try:
+            tree = get_ast(py_file)
+            for node in ast.walk(tree):
+                if isinstance(node, ast.ImportFrom):
+                    main_mod_name = node.module
+                    if main_mod_name == "PySide6.QtCore":
+                        # considers 'from PySide6.QtCore import QtMicrophonePermission'
+                        for imported_module in node.names:
+                            full_mod_name = imported_module.name
+                            match = mod_pattern.search(full_mod_name)
+                            if match:
+                                mod_name = match.group("mod_name")
+                                perm_categories.append(mod_name)
+                        continue
+
+                if isinstance(node, ast.Import):
+                    for imported_module in node.names:
+                        full_mod_name = imported_module.name
+                        if full_mod_name == "PySide6":
+                            logging.warning(IMPORT_WARNING_PYSIDE.format(str(py_file)))
+        except Exception as e:
+            raise RuntimeError(f"[DEPLOY] Finding permission categories failed on file "
+                               f"{str(py_file)} with error {e}")
+
+        return set(perm_categories)
+
+    py_candidates = get_py_files(project_dir, extra_ignore_dirs, project_data)
+    for py_candidate in py_candidates:
+        all_perm_categories = all_perm_categories.union(pyside_permission_imports(py_candidate))
+
+    if not all_perm_categories:
+        ValueError("[DEPLOY] No permission categories were found for macOS app bundle creation.")
+
+    return all_perm_categories
+
+
+def find_pyside_modules(project_dir: Path, extra_ignore_dirs: List[Path] = None,
+                        project_data=None):
+    """
+    Searches all the python files in the project to find all the PySide modules used by
+    the application.
+    """
+    all_modules = set()
+    mod_pattern = re.compile("PySide6.Qt(?P<mod_name>.*)")
+
+    def pyside_module_imports(py_file: Path):
+        modules = []
+        try:
+            tree = get_ast(py_file)
+            for node in ast.walk(tree):
+                if isinstance(node, ast.ImportFrom):
+                    main_mod_name = node.module
+                    if main_mod_name.startswith("PySide6"):
+                        if main_mod_name == "PySide6":
+                            # considers 'from PySide6 import QtCore'
+                            for imported_module in node.names:
+                                full_mod_name = imported_module.name
+                                if full_mod_name.startswith("Qt"):
+                                    modules.append(full_mod_name[2:])
+                            continue
+
+                        # considers 'from PySide6.QtCore import Qt'
+                        match = mod_pattern.search(main_mod_name)
+                        if match:
+                            mod_name = match.group("mod_name")
+                            modules.append(mod_name)
+                        else:
+                            logging.warning((
+                                f"[DEPLOY] Unable to find module name from {ast.dump(node)}"))
+
+                if isinstance(node, ast.Import):
+                    for imported_module in node.names:
+                        full_mod_name = imported_module.name
+                        if full_mod_name == "PySide6":
+                            logging.warning(IMPORT_WARNING_PYSIDE.format(str(py_file)))
+        except Exception as e:
+            raise RuntimeError(f"[DEPLOY] Finding module import failed on file {str(py_file)} with "
+                               f"error {e}")
+
+        return set(modules)
+
+    py_candidates = get_py_files(project_dir, extra_ignore_dirs, project_data)
+    for py_candidate in py_candidates:
+        all_modules = all_modules.union(pyside_module_imports(py_candidate))
+
+    if not all_modules:
+        ValueError("[DEPLOY] No PySide6 modules were found")
+
+    return list(all_modules)
+
+
+class QtDependencyReader:
+    def __init__(self, dry_run: bool = False) -> None:
+        self.dry_run = dry_run
+        self.lib_reader_name = None
+        self.qt_module_path_pattern = None
+        self.lib_pattern = None
+        self.command = None
+        self.qt_libs_dir = None
+
+        if sys.platform == "linux":
+            self.lib_reader_name = "readelf"
+            self.qt_module_path_pattern = "libQt6{module}.so.6"
+            self.lib_pattern = re.compile("libQt6(?P<mod_name>.*).so.6")
+            self.command_args = "-d"
+        elif sys.platform == "darwin":
+            self.lib_reader_name = "dyld_info"
+            self.qt_module_path_pattern = "Qt{module}.framework/Versions/A/Qt{module}"
+            self.lib_pattern = re.compile("@rpath/Qt(?P<mod_name>.*).framework/Versions/A/")
+            self.command_args = "-dependents"
+        elif sys.platform == "win32":
+            self.lib_reader_name = "dumpbin"
+            self.qt_module_path_pattern = "Qt6{module}.dll"
+            self.lib_pattern = re.compile("Qt6(?P<mod_name>.*).dll")
+            self.command_args = "/dependents"
+        else:
+            print(f"[DEPLOY] Deployment on unsupported platfrom {sys.platform}")
+            sys.exit(1)
+
+        self.pyside_install_dir = None
+        self.qt_libs_dir = self.get_qt_libs_dir()
+        self._lib_reader = shutil.which(self.lib_reader_name)
+
+    def get_qt_libs_dir(self):
+        """
+        Finds the path to the Qt libs directory inside PySide6 package installation
+        """
+        for possible_site_package in site.getsitepackages():
+            if possible_site_package.endswith("site-packages"):
+                self.pyside_install_dir = Path(possible_site_package) / "PySide6"
+
+        if not self.pyside_install_dir:
+            print("Unable to find site-packages. Exiting ...")
+            sys.exit(-1)
+
+        if sys.platform == "win32":
+            return self.pyside_install_dir
+
+        return self.pyside_install_dir / "Qt" / "lib"  # for linux and macOS
+
+    @property
+    def lib_reader(self):
+        return self._lib_reader
+
+    def find_dependencies(self, module: str, used_modules: Set[str] = None):
+        """
+        Given a Qt module, find all the other Qt modules it is dependent on and add it to the
+        'used_modules' set
+        """
+        qt_module_path = self.qt_libs_dir / self.qt_module_path_pattern.format(module=module)
+        if not qt_module_path.exists():
+            warnings.warn(f"[DEPLOY] {qt_module_path.name} not found in {str(qt_module_path)}."
+                          "Skipping finding its dependencies.", category=RuntimeWarning)
+            return
+
+        lib_pattern = re.compile(self.lib_pattern)
+        command = [self.lib_reader, self.command_args, str(qt_module_path)]
+        # print the command if dry_run is True.
+        # Normally run_command is going to print the command in dry_run mode. But, this is a
+        # special case where we need to print the command as well as to run it.
+        if self.dry_run:
+            command_str = " ".join(command)
+            print(command_str + "\n")
+
+        # We need to run this even for dry run, to see the full Nuitka command being executed
+        _, output = run_command(command=command, dry_run=False, fetch_output=True)
+
+        dependent_modules = set()
+        for line in output.splitlines():
+            line = line.decode("utf-8").lstrip()
+            if sys.platform == "darwin":
+                if line.endswith(f"Qt{module} [arm64]:"):
+                    # macOS Qt frameworks bundles have both x86_64 and arm64 architectures
+                    # We only need to consider one as the dependencies are redundant
+                    break
+                elif line.endswith(f"Qt{module} [X86_64]:"):
+                    # this line needs to be skipped because it matches with the pattern
+                    # and is related to the module itself, not the dependencies of the module
+                    continue
+            elif sys.platform == "win32" and line.startswith("Summary"):
+                # the dependencies would be found before the `Summary` line
+                break
+            match = lib_pattern.search(line)
+            if match:
+                dep_module = match.group("mod_name")
+                dependent_modules.add(dep_module)
+                if dep_module not in used_modules:
+                    used_modules.add(dep_module)
+                    self.find_dependencies(module=dep_module, used_modules=used_modules)
+
+        if dependent_modules:
+            logging.info(f"[DEPLOY] Following dependencies found for {module}: {dependent_modules}")
+        else:
+            logging.info(f"[DEPLOY] No Qt dependencies found for {module}")
+
+    def find_plugin_dependencies(self, used_modules: List[str], python_exe: Path) -> List[str]:
+        """
+        Given the modules used by the application, returns all the required plugins
+        """
+        plugins = set()
+        pyside_wheels = ["PySide6_Essentials", "PySide6_Addons"]
+        # TODO from 3.12 use list(dist.name for dist in importlib.metadata.distributions())
+        _, installed_packages = run_command(command=[str(python_exe), "-m", "pip", "freeze"],
+                                            dry_run=False, fetch_output=True)
+        installed_packages = [p.decode().split('==')[0] for p in installed_packages.split()]
+        for pyside_wheel in pyside_wheels:
+            if pyside_wheel not in installed_packages:
+                # the wheel is not installed and hence no plugins are checked for its modules
+                logging.warning((f"[DEPLOY] The package {pyside_wheel} is not installed. "))
+                continue
+            pyside_mod_plugin_json_name = f"{pyside_wheel}.json"
+            pyside_mod_plugin_json_file = self.pyside_install_dir / pyside_mod_plugin_json_name
+            if not pyside_mod_plugin_json_file.exists():
+                warnings.warn(f"[DEPLOY] Unable to find {pyside_mod_plugin_json_file}.",
+                              category=RuntimeWarning)
+                continue
+
+            # convert the json to dict
+            pyside_mod_dict = {}
+            with open(pyside_mod_plugin_json_file) as pyside_json:
+                pyside_mod_dict = json.load(pyside_json)
+
+            # find all the plugins in the modules
+            for module in used_modules:
+                plugins.update(pyside_mod_dict.get(module, []))
+
+        return list(plugins)
index a8ca586118f5dc86f1225a799d5ed48405250379..e8b05e9904e40facb3fd92ab034d42d2d1fb02c2 100644 (file)
@@ -8,7 +8,6 @@ from pathlib import Path
 
 from . import EXE_FORMAT
 from .config import Config
-from .python_helper import PythonExecutable
 
 
 def config_option_exists():
@@ -62,49 +61,6 @@ def create_config_file(dry_run: bool = False, config_file: Path = None, main_fil
     return config_file
 
 
-def setup_python(dry_run: bool, force: bool, init: bool):
-    """
-        Sets up Python venv for deployment, and return a wrapper around the venv environment
-    """
-    python = None
-    response = "yes"
-    # checking if inside virtual environment
-    if not PythonExecutable.is_venv() and not force and not dry_run and not init:
-        response = input(("You are not using a virtual environment. pyside6-deploy needs to install"
-                          " a few Python packages for deployment to work seamlessly. \n"
-                          "Proceed? [Y/n]"))
-
-    if response.lower() in ["no", "n"]:
-        print("[DEPLOY] Exiting ...")
-        sys.exit(0)
-
-    python = PythonExecutable(dry_run=dry_run)
-    logging.info(f"[DEPLOY] Using python at {sys.executable}")
-
-    return python
-
-
-def install_python_dependencies(config: Config, python: PythonExecutable, init: bool,
-                                packages: str, is_android: bool = False):
-    """
-        Installs the python package dependencies for the target deployment platform
-    """
-    packages = config.get_value("python", packages).split(",")
-    if not init:
-        # install packages needed for deployment
-        logging.info("[DEPLOY] Installing dependencies")
-        python.install(packages=packages)
-        # nuitka requires patchelf to make patchelf rpath changes for some Qt files
-        if sys.platform.startswith("linux") and not is_android:
-            python.install(packages=["patchelf"])
-    elif is_android:
-        # install only buildozer
-        logging.info("[DEPLOY] Installing buildozer")
-        buildozer_package_with_version = ([package for package in packages
-                                          if package.startswith("buildozer")])
-        python.install(packages=list(buildozer_package_with_version))
-
-
 def finalize(config: Config):
     """
         Copy the executable into the final location
@@ -112,6 +68,10 @@ def finalize(config: Config):
     """
     generated_exec_path = config.generated_files_path / (config.source_file.stem + EXE_FORMAT)
     if generated_exec_path.exists() and config.exe_dir:
-        shutil.copy(generated_exec_path, config.exe_dir)
+        if sys.platform == "darwin":
+            shutil.copytree(generated_exec_path, config.exe_dir / (config.title + EXE_FORMAT),
+                            dirs_exist_ok=True)
+        else:
+            shutil.copy(generated_exec_path, config.exe_dir)
         print("[DEPLOY] Executed file created in "
               f"{str(config.exe_dir / (config.source_file.stem + EXE_FORMAT))}")
index ae5834b6bd8651f391749e85f7ca0116bff1a3ae..ac9a83f3f1355167bf5dbb5d3055151b4bd4a5b7 100644 (file)
@@ -17,6 +17,29 @@ class Nuitka:
 
     def __init__(self, nuitka):
         self.nuitka = nuitka
+        # plugins to ignore. The sensible plugins are include by default by Nuitka for PySide6
+        # application deployment
+        self.qt_plugins_to_ignore = ["imageformats",  # being Nuitka `sensible`` plugins
+                                     "iconengines",
+                                     "mediaservice",
+                                     "printsupport",
+                                     "platforms",
+                                     "platformthemes",
+                                     "styles",
+                                     "wayland-shell-integration",
+                                     "wayland-decoration-client",
+                                     "wayland-graphics-integration-client",
+                                     "egldeviceintegrations",
+                                     "xcbglintegrations",
+                                     "tls",  # end Nuitka `sensible` plugins
+                                     "generic"  # plugins that error with Nuitka
+                                     ]
+
+        # .webp are considered to be dlls by Nuitka instead of data files causing
+        # the packaging to fail
+        # https://github.com/Nuitka/Nuitka/issues/2854
+        # TODO: Remove .webp when the issue is fixed
+        self.files_to_ignore = [".cpp.o", ".qsb", ".webp"]
 
     @staticmethod
     def icon_option():
@@ -28,11 +51,22 @@ class Nuitka:
             return "--macos-app-icon"
 
     def create_executable(self, source_file: Path, extra_args: str, qml_files: List[Path],
-                          excluded_qml_plugins: List[str], icon: str, dry_run: bool):
+                          qt_plugins: List[str], excluded_qml_plugins: List[str], icon: str,
+                          dry_run: bool, permissions: List[str]):
+        qt_plugins = [plugin for plugin in qt_plugins if plugin not in self.qt_plugins_to_ignore]
         extra_args = extra_args.split()
+
+        if sys.platform == "darwin":
+            # create an app bundle
+            extra_args.extend(["--standalone", "--macos-create-app-bundle"])
+            permission_pattern = "--macos-app-protected-resource={permission}"
+            for permission in permissions:
+                extra_args.append(permission_pattern.format(permission=permission))
+        else:
+            extra_args.append("--onefile")
+
         qml_args = []
         if qml_files:
-            qml_args.append("--include-qt-plugins=all")
             # This will generate options for each file using:
             #     --include-data-files=ABSOLUTE_PATH_TO_FILE=RELATIVE_PATH_TO ROOT
             # for each file. This will preserve the directory structure of QML resources.
@@ -41,6 +75,11 @@ class Nuitka:
                  f"./{qml_file.resolve().relative_to(source_file.parent)}"
                  for qml_file in qml_files]
             )
+            # add qml plugin. The `qml`` plugin name is not present in the module json files shipped
+            # with Qt and hence not in `qt_plugins``. However, Nuitka uses the 'qml' plugin name to
+            # include the necessary qml plugins. There we have to add it explicitly for a qml
+            # application
+            qt_plugins.append("qml")
 
             if excluded_qml_plugins:
                 prefix = "lib" if sys.platform != "win32" else ""
@@ -48,6 +87,14 @@ class Nuitka:
                     dll_name = plugin.replace("Qt", f"Qt{MAJOR_VERSION}")
                     qml_args.append(f"--noinclude-dlls={prefix}{dll_name}*")
 
+            # Exclude .qen json files from QtQuickEffectMaker
+            # These files are not relevant for PySide6 applications
+            qml_args.append("--noinclude-dlls=*/qml/QtQuickEffectMaker/*")
+
+        # Exclude files that cannot be processed by Nuitka
+        for file in self.files_to_ignore:
+            extra_args.append(f"--noinclude-dlls=*{file}")
+
         output_dir = source_file.parent / "deployment"
         if not dry_run:
             output_dir.mkdir(parents=True, exist_ok=True)
@@ -55,12 +102,17 @@ class Nuitka:
         command = self.nuitka + [
             os.fspath(source_file),
             "--follow-imports",
-            "--onefile",
             "--enable-plugin=pyside6",
             f"--output-dir={output_dir}",
         ]
+
         command.extend(extra_args + qml_args)
         command.append(f"{self.__class__.icon_option()}={icon}")
+        if qt_plugins:
+            # sort qt_plugins so that the result is definitive when testing
+            qt_plugins.sort()
+            qt_plugins_str = ",".join(qt_plugins)
+            command.append(f"--include-qt-plugins={qt_plugins_str}")
 
         command_str, _ = run_command(command=command, dry_run=dry_run)
         return command_str
index 6ec3b64f87d47c17ed3a87c85fe7d067df7295c7..7cbf323ed89fa9313c2390dc0f18fe56b01ac662 100644 (file)
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
-import ast
 import logging
 import os
-import re
 import sys
-import warnings
-from typing import List
+
 from importlib import util
 from importlib.metadata import version
 from pathlib import Path
 
-from . import Nuitka, run_command
-
-IMPORT_WARNING_PYSIDE = (f"[DEPLOY] Found 'import PySide6' in file {0}"
-                         ". Use 'from PySide6 import <module>' or pass the module"
-                         " needed using --extra-modules command line argument")
-
-
-def find_pyside_modules(project_dir: Path, extra_ignore_dirs: List[Path] = None,
-                        project_data=None):
-    """
-    Searches all the python files in the project to find all the PySide modules used by
-    the application.
-    """
-    all_modules = set()
-    mod_pattern = re.compile("PySide6.Qt(?P<mod_name>.*)")
-
-    def pyside_imports(py_file: Path):
-        modules = []
-        contents = py_file.read_text(encoding="utf-8")
-        try:
-            tree = ast.parse(contents)
-            for node in ast.walk(tree):
-                if isinstance(node, ast.ImportFrom):
-                    main_mod_name = node.module
-                    if main_mod_name.startswith("PySide6"):
-                        if main_mod_name == "PySide6":
-                            # considers 'from PySide6 import QtCore'
-                            for imported_module in node.names:
-                                full_mod_name = imported_module.name
-                                if full_mod_name.startswith("Qt"):
-                                    modules.append(full_mod_name[2:])
-                            continue
-
-                        # considers 'from PySide6.QtCore import Qt'
-                        match = mod_pattern.search(main_mod_name)
-                        if match:
-                            mod_name = match.group("mod_name")
-                            modules.append(mod_name)
-                        else:
-                            logging.warning((
-                                f"[DEPLOY] Unable to find module name from{ast.dump(node)}"))
-
-                if isinstance(node, ast.Import):
-                    for imported_module in node.names:
-                        full_mod_name = imported_module.name
-                        if full_mod_name == "PySide6":
-                            logging.warning(IMPORT_WARNING_PYSIDE.format(str(py_file)))
-        except Exception as e:
-            raise RuntimeError(f"[DEPLOY] Finding module import failed on file {str(py_file)} with "
-                               f"error {e}")
-
-        return set(modules)
-
-    py_candidates = []
-    ignore_dirs = ["__pycache__", "env", "venv", "deployment"]
-
-    if project_data:
-        py_candidates = project_data.python_files
-        ui_candidates = project_data.ui_files
-        qrc_candidates = project_data.qrc_files
-        ui_py_candidates = None
-        qrc_ui_candidates = None
-
-        if ui_candidates:
-            ui_py_candidates = [(file.parent / f"ui_{file.stem}.py") for file in ui_candidates
-                                if (file.parent / f"ui_{file.stem}.py").exists()]
-
-            if len(ui_py_candidates) != len(ui_candidates):
-                warnings.warn("[DEPLOY] The number of uic files and their corresponding Python"
-                              " files don't match.", category=RuntimeWarning)
-
-            py_candidates.extend(ui_py_candidates)
-
-        if qrc_candidates:
-            qrc_ui_candidates = [(file.parent / f"rc_{file.stem}.py") for file in qrc_candidates
-                                 if (file.parent / f"rc_{file.stem}.py").exists()]
-
-            if len(qrc_ui_candidates) != len(qrc_candidates):
-                warnings.warn("[DEPLOY] The number of qrc files and their corresponding Python"
-                              " files don't match.", category=RuntimeWarning)
-
-            py_candidates.extend(qrc_ui_candidates)
-
-        for py_candidate in py_candidates:
-            all_modules = all_modules.union(pyside_imports(py_candidate))
-        return list(all_modules)
-
-    # incase there is not .pyproject file, search all python files in project_dir, except
-    # ignore_dirs
-    if extra_ignore_dirs:
-        ignore_dirs.extend(extra_ignore_dirs)
-
-    # find relevant .py files
-    _walk = os.walk(project_dir)
-    for root, dirs, files in _walk:
-        dirs[:] = [d for d in dirs if d not in ignore_dirs and not d.startswith(".")]
-        for py_file in files:
-            if py_file.endswith(".py"):
-                py_candidates.append(Path(root) / py_file)
-
-    for py_candidate in py_candidates:
-        all_modules = all_modules.union(pyside_imports(py_candidate))
-
-    if not all_modules:
-        ValueError("[DEPLOY] No PySide6 modules were found")
-
-    return list(all_modules)
+from . import Config, run_command
 
 
 class PythonExecutable:
@@ -126,10 +17,28 @@ class PythonExecutable:
     Wrapper class around Python executable
     """
 
-    def __init__(self, python_path=None, dry_run=False):
-        self.exe = python_path if python_path else Path(sys.executable)
+    def __init__(self, python_path: Path = None, dry_run: bool = False, init: bool = False,
+                 force: bool = False):
+
         self.dry_run = dry_run
-        self.nuitka = Nuitka(nuitka=[os.fspath(self.exe), "-m", "nuitka"])
+        self.init = init
+        if not python_path:
+            response = "yes"
+            # checking if inside virtual environment
+            if not self.is_venv() and not force and not self.dry_run and not self.init:
+                response = input(("You are not using a virtual environment. pyside6-deploy needs "
+                                  "to install a few Python packages for deployment to work "
+                                  "seamlessly. \n Proceed? [Y/n]"))
+
+            if response.lower() in ["no", "n"]:
+                print("[DEPLOY] Exiting ...")
+                sys.exit(0)
+
+            self.exe = Path(sys.executable)
+        else:
+            self.exe = python_path
+
+        logging.info(f"[DEPLOY] Using Python at {str(self.exe)}")
 
     @property
     def exe(self):
@@ -193,16 +102,21 @@ class PythonExecutable:
     def is_installed(self, package):
         return bool(util.find_spec(package))
 
-    def create_executable(self, source_file: Path, extra_args: str, config):
-        if config.qml_files:
-            logging.info(f"[DEPLOY] Included QML files: {config.qml_files}")
-
-        command_str = self.nuitka.create_executable(source_file=source_file,
-                                                    extra_args=extra_args,
-                                                    qml_files=config.qml_files,
-                                                    excluded_qml_plugins=(config.
-                                                                          excluded_qml_plugins),
-                                                    icon=config.icon,
-                                                    dry_run=self.dry_run)
-
-        return command_str
+    def install_dependencies(self, config: Config, packages: str, is_android: bool = False):
+        """
+        Installs the python package dependencies for the target deployment platform
+        """
+        packages = config.get_value("python", packages).split(",")
+        if not self.init:
+            # install packages needed for deployment
+            logging.info("[DEPLOY] Installing dependencies")
+            self.install(packages=packages)
+            # nuitka requires patchelf to make patchelf rpath changes for some Qt files
+            if sys.platform.startswith("linux") and not is_android:
+                self.install(packages=["patchelf"])
+        elif is_android:
+            # install only buildozer
+            logging.info("[DEPLOY] Installing buildozer")
+            buildozer_package_with_version = ([package for package in packages
+                                               if package.startswith("buildozer")])
+            self.install(packages=list(buildozer_package_with_version))
index bc84708cb2195cfd73bf8a7347adaae4f330cc0f..0970f9974f02bf7566bd498ea2902a81f7a07342 100644 (file)
@@ -39,6 +39,7 @@ QOBJECT_DERIVED = ["QObject", "QQuickItem", "QQuickPaintedItem"] + ITEM_MODELS
 
 
 AstDecorator = Union[ast.Name, ast.Call]
+AstPySideTypeSpec = Union[ast.Name, ast.Constant]
 
 
 ClassList = List[dict]
@@ -96,12 +97,20 @@ def _parse_assignment(node: ast.Assign) -> Tuple[Optional[str], Optional[ast.AST
     return (None, None)
 
 
+def _parse_pyside_type(type_spec: AstPySideTypeSpec) -> str:
+    """Parse type specification of a Slot/Property decorator. Usually a type,
+       but can also be a string constant with a C++ type name."""
+    if isinstance(type_spec, ast.Constant):
+        return type_spec.value
+    return _python_to_cpp_type(_name(type_spec))
+
+
 def _parse_call_args(call: ast.Call):
     """Parse arguments of a Signal call/Slot decorator (type list)."""
     result: Arguments = []
     for n, arg in enumerate(call.args):
         par_name = f"a{n+1}"
-        par_type = _python_to_cpp_type(_name(arg))
+        par_type = _parse_pyside_type(arg)
         result.append({"name": par_name, "type": par_type})
     return result
 
@@ -264,7 +273,7 @@ class MetaObjectDumpVisitor(ast.NodeVisitor):
             elif name == "QmlNamedElement" and node.args:
                 name = node.args[0].value
                 class_decorators.append(_decorator("QML.Element", name))
-            else:
+            elif name.startswith('Q'):
                 print('Unknown decorator with parameters:', name,
                       file=sys.stderr)
             return
@@ -277,7 +286,7 @@ class MetaObjectDumpVisitor(ast.NodeVisitor):
                 class_decorators.append(_decorator("QML.Singleton", "true"))
             elif name == "QmlAnonymous":
                 class_decorators.append(_decorator("QML.Element", "anonymous"))
-            else:
+            elif name.startswith('Q'):
                 print('Unknown decorator:', name, file=sys.stderr)
             return
 
@@ -311,8 +320,8 @@ class MetaObjectDumpVisitor(ast.NodeVisitor):
         if isinstance(node, ast.Call):
             name = _name(node.func)
             if name == "Property":  # Property getter
-                if node.args:  # 1st is type
-                    type = _python_to_cpp_type(_name(node.args[0]))
+                if node.args:  # 1st is type/type string
+                    type = _parse_pyside_type(node.args[0])
                     prop = self._create_property_entry(func_name, type,
                                                        func_name)
                     _parse_property_kwargs(node.keywords, prop)
index 621bf1ac75950a570f59f3145801d371329958d2..3706a29859300032b1e14f4a8ed6fe5ef164d5f9 100644 (file)
@@ -27,15 +27,17 @@ from argparse import ArgumentParser, RawTextHelpFormatter
 
 from project import (QmlProjectData, check_qml_decorators, is_python_file,
                      QMLDIR_FILE, MOD_CMD, METATYPES_JSON_SUFFIX,
+                     SHADER_SUFFIXES, TRANSLATION_SUFFIX,
                      requires_rebuild, run_command, remove_path,
                      ProjectData, resolve_project_file, new_project,
-                     ProjectType)
+                     ProjectType, ClOptions)
 
 MODE_HELP = """build    Builds the project
 run        Builds the project and runs the first file")
 clean      Cleans the build artifacts")
 qmllint    Runs the qmllint tool
 deploy     Deploys the application
+lupdate    Updates translation (.ts) files
 new-ui     Creates a new QtWidgets project with a Qt Designer-based main window
 new-widget Creates a new QtWidgets project with a main window
 new-quick  Creates a new QtQuick project
@@ -43,8 +45,11 @@ new-quick  Creates a new QtQuick project
 
 UIC_CMD = "pyside6-uic"
 RCC_CMD = "pyside6-rcc"
+LRELEASE_CMD = "pyside6-lrelease"
+LUPDATE_CMD = "pyside6-lupdate"
 QMLTYPEREGISTRAR_CMD = "pyside6-qmltyperegistrar"
 QMLLINT_CMD = "pyside6-qmllint"
+QSB_CMD = "pyside6-qsb"
 DEPLOY_CMD = "pyside6-deploy"
 
 NEW_PROJECT_TYPES = {"new-quick": ProjectType.QUICK,
@@ -52,12 +57,23 @@ NEW_PROJECT_TYPES = {"new-quick": ProjectType.QUICK,
                      "new-widget": ProjectType.WIDGET}
 
 
+def _sort_sources(files: List[Path]) -> List[Path]:
+    """Sort the sources for building, ensure .qrc is last since it might depend
+       on generated files."""
+
+    def key_func(p: Path):
+        return p.suffix if p.suffix != ".qrc" else ".zzzz"
+
+    return sorted(files, key=key_func)
+
+
 class Project:
     """
     Class to wrap the various operations on Project
     """
     def __init__(self, project_file: Path):
         self.project = ProjectData(project_file=project_file)
+        self.cl_options = ClOptions()
 
         # Files for QML modules using the QmlElement decorators
         self._qml_module_sources: List[Path] = []
@@ -70,7 +86,7 @@ class Project:
         """Run a pre-check on Python source files and find the ones with QML
         decorators (representing a QML module)."""
         # Quick check for any QML files (to avoid running moc for no reason).
-        if not opt_qml_module and not self.project.qml_files:
+        if not self.cl_options.qml_module and not self.project.qml_files:
             return
         for file in self.project.files:
             if is_python_file(file):
@@ -92,7 +108,7 @@ class Project:
         print(self._qml_module_dir)
         self._qml_dir_file = self._qml_module_dir / QMLDIR_FILE
 
-        if not opt_quiet:
+        if not self.cl_options.quiet:
             count = len(self._qml_module_sources)
             print(f"{self.project.project_file.name}, {count} QML file(s),"
                   f" {self._qml_project_data}")
@@ -123,13 +139,23 @@ class Project:
             cmd.extend(self._qml_project_data.registrar_options())
             return ([qmltypes_file, cpp_file], cmd)
 
+        if file.name.endswith(TRANSLATION_SUFFIX):
+            qm_file = f"{file.parent}/{file.stem}.qm"
+            cmd = [LRELEASE_CMD, os.fspath(file), "-qm", qm_file]
+            return ([Path(qm_file)], cmd)
+
+        if file.suffix in SHADER_SUFFIXES:
+            qsb_file = f"{file.parent}/{file.stem}.qsb"
+            cmd = [QSB_CMD, "-o", qsb_file, os.fspath(file)]
+            return ([Path(qsb_file)], cmd)
+
         return ([], None)
 
     def _regenerate_qmldir(self):
         """Regenerate the 'qmldir' file."""
-        if opt_dry_run or not self._qml_dir_file:
+        if self.cl_options.dry_run or not self._qml_dir_file:
             return
-        if opt_force or requires_rebuild(self._qml_module_sources, self._qml_dir_file):
+        if self.cl_options.force or requires_rebuild(self._qml_module_sources, self._qml_dir_file):
             with self._qml_dir_file.open("w") as qf:
                 qf.write(f"module {self._qml_project_data.import_name}\n")
                 for f in self._qml_module_dir.glob("*.qmltypes"):
@@ -139,7 +165,7 @@ class Project:
         """Build an artifact."""
         artifacts, command = self._get_artifacts(source)
         for artifact in artifacts:
-            if opt_force or requires_rebuild([source], artifact):
+            if self.cl_options.force or requires_rebuild([source], artifact):
                 run_command(command, cwd=self.project.project_file.parent)
             self._build_file(artifact)  # Recurse for QML (json->qmltypes)
 
@@ -149,7 +175,7 @@ class Project:
             Project(project_file=sub_project_file).build()
         if self._qml_module_dir:
             self._qml_module_dir.mkdir(exist_ok=True, parents=True)
-        for file in self.project.files:
+        for file in _sort_sources(self.project.files):
             self._build_file(file)
         self._regenerate_qmldir()
 
@@ -207,6 +233,24 @@ class Project:
         cmd.extend([str(self.project.main_file), "-f"])
         run_command(cmd, cwd=self.project.project_file.parent)
 
+    def lupdate(self):
+        for sub_project_file in self.project.sub_projects_files:
+            Project(project_file=sub_project_file).lupdate()
+
+        if not self.project.ts_files:
+            print(f"{self.project.project_file.name}: No .ts file found.",
+                  file=sys.stderr)
+            return
+
+        source_files = self.project.python_files + self.project.ui_files
+        cmd_prefix = [LUPDATE_CMD] + [p.name for p in source_files]
+        cmd_prefix.append("-ts")
+        for ts_file in self.project.ts_files:
+            if requires_rebuild(source_files, ts_file):
+                cmd = cmd_prefix
+                cmd.append(ts_file.name)
+                run_command(cmd, cwd=self.project.project_file.parent)
+
 
 if __name__ == "__main__":
     parser = ArgumentParser(description=__doc__, formatter_class=RawTextHelpFormatter)
@@ -215,17 +259,16 @@ if __name__ == "__main__":
     parser.add_argument("--force", "-f", action="store_true", help="Force rebuild")
     parser.add_argument("--qml-module", "-Q", action="store_true",
                         help="Perform check for QML module")
-    mode_choices = ["build", "run", "clean", "qmllint", "deploy"]
+    mode_choices = ["build", "run", "clean", "qmllint", "deploy", "lupdate"]
     mode_choices.extend(NEW_PROJECT_TYPES.keys())
     parser.add_argument("mode", choices=mode_choices, default="build",
                         type=str, help=MODE_HELP)
     parser.add_argument("file", help="Project file", nargs="?", type=str)
 
     options = parser.parse_args()
-    opt_quiet = options.quiet
-    opt_dry_run = options.dry_run
-    opt_force = options.force
-    opt_qml_module = options.qml_module
+    cl_options = ClOptions(dry_run=options.dry_run, quiet=options.quiet, force=options.force,
+                           qml_module=options.qml_module)
+
     mode = options.mode
 
     new_project_type = NEW_PROJECT_TYPES.get(mode)
@@ -250,6 +293,8 @@ if __name__ == "__main__":
         project.qmllint()
     elif mode == "deploy":
         project.deploy()
+    elif mode == "lupdate":
+        project.lupdate()
     else:
         print(f"Invalid mode {mode}", file=sys.stderr)
         sys.exit(1)
index be99555b148efc68334e36c140e106bc6cf8b76e..e57a9ff889f0b7e1d746f89494c177b6b0ae4e6e 100644 (file)
@@ -1,10 +1,7 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
-opt_quiet = False
-opt_dry_run = False
-opt_force = False
-opt_qml_module = False
+from dataclasses import dataclass
 
 QTPATHS_CMD = "qtpaths6"
 MOD_CMD = "pyside6-metaobjectdump"
@@ -18,6 +15,29 @@ QML_IMPORT_MINOR_VERSION = "QML_IMPORT_MINOR_VERSION"
 QT_MODULES = "QT_MODULES"
 
 METATYPES_JSON_SUFFIX = "metatypes.json"
+TRANSLATION_SUFFIX = ".ts"
+SHADER_SUFFIXES = ".vert", ".frag"
+
+
+class Singleton(type):
+    _instances = {}
+
+    def __call__(cls, *args, **kwargs):
+        if cls not in cls._instances:
+            cls._instances[cls] = super().__call__(*args, **kwargs)
+        return cls._instances[cls]
+
+
+@dataclass(frozen=True)
+class ClOptions(metaclass=Singleton):
+    """
+    Dataclass to store the cl options that needs to be passed as arguments.
+    """
+    dry_run: bool
+    quiet: bool
+    force: bool
+    qml_module: bool
+
 
 from .utils import (run_command, requires_rebuild, remove_path, package_dir, qtpaths,
                     qt_metatype_json_dir, resolve_project_file)
index 416089dce0db90ee20f0cfff6b50e0998e2826d3..52e20be3f4dad67839788387df399decc500df65 100644 (file)
@@ -7,9 +7,9 @@ import subprocess
 import sys
 from typing import List, Tuple
 from pathlib import Path
-from . import (METATYPES_JSON_SUFFIX, PROJECT_FILE_SUFFIX, qt_metatype_json_dir,
-               MOD_CMD, QML_IMPORT_MAJOR_VERSION, QML_IMPORT_MINOR_VERSION, QML_IMPORT_NAME,
-               QT_MODULES)
+from . import (METATYPES_JSON_SUFFIX, PROJECT_FILE_SUFFIX, TRANSLATION_SUFFIX,
+               qt_metatype_json_dir, MOD_CMD, QML_IMPORT_MAJOR_VERSION,
+               QML_IMPORT_MINOR_VERSION, QML_IMPORT_NAME, QT_MODULES)
 
 
 def is_python_file(file: Path) -> bool:
@@ -34,6 +34,8 @@ class ProjectData:
         self._ui_files: List[Path] = []
         # qrc files
         self._qrc_files: List[Path] = []
+        # ts files
+        self._ts_files: List[Path] = []
 
         with project_file.open("r") as pyf:
             pyproject = json.load(pyf)
@@ -53,6 +55,8 @@ class ProjectData:
                         self._ui_files.append(file)
                     elif file.suffix == ".qrc":
                         self._qrc_files.append(file)
+                    elif file.suffix == TRANSLATION_SUFFIX:
+                        self._ts_files.append(file)
 
         if not self.main_file:
             self._find_main_file()
@@ -89,6 +93,10 @@ class ProjectData:
     def qml_files(self):
         return self._qml_files
 
+    @property
+    def ts_files(self):
+        return self._ts_files
+
     @property
     def sub_projects_files(self):
         return self._sub_projects_files
index b3fd03584d688927aa41d4a04505a4777f03b628..d2bff65afe78dbda617570140060a3be6cd4458f 100644 (file)
@@ -6,14 +6,15 @@ import subprocess
 from pathlib import Path
 from typing import List, Dict, Optional
 
-from . import opt_dry_run, opt_quiet, QTPATHS_CMD, PROJECT_FILE_SUFFIX
+from . import QTPATHS_CMD, PROJECT_FILE_SUFFIX, ClOptions
 
 
 def run_command(command: List[str], cwd: str = None, ignore_fail: bool = False):
     """Run a command observing quiet/dry run"""
-    if not opt_quiet or opt_dry_run:
+    cloptions = ClOptions()
+    if not cloptions.quiet or cloptions.dry_run:
         print(" ".join(command))
-    if not opt_dry_run:
+    if not cloptions.dry_run:
         ex = subprocess.call(command, cwd=cwd)
         if ex != 0 and not ignore_fail:
             sys.exit(ex)
@@ -42,11 +43,12 @@ def _remove_path_recursion(path: Path):
 
 def remove_path(path: Path):
     """Remove path (file or directory) observing opt_dry_run."""
+    cloptions = ClOptions()
     if not path.exists():
         return
-    if not opt_quiet:
+    if not cloptions.quiet:
         print(f"Removing {path.name}...")
-    if opt_dry_run:
+    if cloptions.dry_run:
         return
     _remove_path_recursion(path)
 
index 7daacc22d5f2289ebe3ee08c34647510687eabcc..b369be8a2a7b284dd6d615bcce7093e48b0a1edc 100644 (file)
@@ -227,5 +227,17 @@ def android_deploy():
         pyside_script_wrapper("android_deploy.py")
 
 
+def qsb():
+    qt_tool_wrapper("qsb", sys.argv[1:])
+
+
+def balsam():
+    qt_tool_wrapper("balsam", sys.argv[1:])
+
+
+def balsamui():
+    qt_tool_wrapper("balsamui", sys.argv[1:])
+
+
 if __name__ == "__main__":
     main()
index d76e5c5c9812ca945a2e745f3060302792ae4c09..5d029f93de72677b0a57c174aba35762435dfdee 100644 (file)
@@ -16,7 +16,7 @@ from typing import List, Set
 from PySide6.QtCore import QCoreApplication, Qt, QLibraryInfo, QUrl, SignalInstance
 from PySide6.QtGui import QGuiApplication, QSurfaceFormat
 from PySide6.QtQml import QQmlApplicationEngine, QQmlComponent
-from PySide6.QtQuick import QQuickView, QQuickWindow
+from PySide6.QtQuick import QQuickView, QQuickItem
 from PySide6.QtWidgets import QApplication
 
 
@@ -227,7 +227,7 @@ if __name__ == "__main__":
         sys.exit(-1)
 
     qquick_view = False
-    if isinstance(rootObjects[0], QQuickWindow) and qquick_present:
+    if isinstance(rootObjects[0], QQuickItem) and qquick_present:
         logging.info("qml: loading with QQuickView")
         viewer = QQuickView()
         viewer.setSource(qml_file)
index 66542fa558f1f95f73108116a2ead1f7c9d7127e..8f6fb6eca201fef48017f2a128cd39b8842f815e 100644 (file)
@@ -1,5 +1,5 @@
 set(pyside_MAJOR_VERSION "6")
-set(pyside_MINOR_VERSION "6")
+set(pyside_MINOR_VERSION "7")
 set(pyside_MICRO_VERSION "2")
 set(pyside_PRE_RELEASE_VERSION_TYPE "")
 set(pyside_PRE_RELEASE_VERSION "")
index 5b6256fc2905ac5f7bcaca09e5f32ba6298cec9f..d9169924e31c55de12c92edff02ecff086550b9e 100644 (file)
@@ -19,6 +19,7 @@ ${Qt3DAnimation_GEN_DIR}/qt3danimation_qanimationcliploader_wrapper.cpp
 ${Qt3DAnimation_GEN_DIR}/qt3danimation_qanimationcontroller_wrapper.cpp
 ${Qt3DAnimation_GEN_DIR}/qt3danimation_qanimationgroup_wrapper.cpp
 ${Qt3DAnimation_GEN_DIR}/qt3danimation_qblendedclipanimator_wrapper.cpp
+${Qt3DAnimation_GEN_DIR}/qt3danimation_qcallbackmapping_wrapper.cpp
 ${Qt3DAnimation_GEN_DIR}/qt3danimation_qchannel_wrapper.cpp
 ${Qt3DAnimation_GEN_DIR}/qt3danimation_qchannelcomponent_wrapper.cpp
 ${Qt3DAnimation_GEN_DIR}/qt3danimation_qchannelmapper_wrapper.cpp
@@ -42,12 +43,14 @@ set(Qt3DAnimation_include_dirs
                      ${pyside6_SOURCE_DIR}
                      ${Qt${QT_MAJOR_VERSION}Core_INCLUDE_DIRS}
                      ${Qt${QT_MAJOR_VERSION}Gui_INCLUDE_DIR}
+                     ${Qt${QT_MAJOR_VERSION}OpenGL_INCLUDE_DIRS}
                      ${Qt${QT_MAJOR_VERSION}3DCore_INCLUDE_DIRS}
                      ${Qt${QT_MAJOR_VERSION}3DRender_INCLUDE_DIRS}
                      ${Qt${QT_MAJOR_VERSION}3DAnimation_INCLUDE_DIRS}
                      ${libpyside_SOURCE_DIR}
                      ${QtCore_GEN_DIR}
                      ${QtGui_GEN_DIR}
+                     ${QtOpenGL_GEN_DIR}
                      ${Qt3DCore_GEN_DIR}
                      ${Qt3DRender_GEN_DIR}
                      ${Qt3DAnimation_GEN_DIR})
index f93a51b59e998f6d9e1d7eacf3b96f8dfbec6171..61af82d6db51e32fecb8c0cc0e5f16edbe99ed04 100644 (file)
@@ -4,7 +4,8 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.Qt3DAnimation">
+<typesystem package="PySide6.Qt3DAnimation"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="Qt3DRender/typesystem_3drender.xml" generate="no"/>
     <namespace-type name="Qt3DAnimation">
         <object-type name="QAbstractAnimation">
@@ -36,6 +37,7 @@
         <object-type name="QBlendedClipAnimator"/>
         <value-type name="QChannel"/>
         <value-type name="QChannelComponent"/>
+        <object-type name="QCallbackMapping"/>
         <object-type name="QChannelMapper" since="6.1"/>
         <object-type name="QChannelMapping"/>
         <object-type name="QClipAnimator"/>
index 5493c68761b2688939e443bf042798a88050f443..cd2699f11e95e4c61ffcd6eeb3f7fe77b575e2d4 100644 (file)
@@ -19,6 +19,7 @@ ${Qt3DCore_GEN_DIR}/qt3dcore_qbackendnodemapper_wrapper.cpp
 ${Qt3DCore_GEN_DIR}/qt3dcore_qboundingvolume_wrapper.cpp
 ${Qt3DCore_GEN_DIR}/qt3dcore_qbuffer_wrapper.cpp
 ${Qt3DCore_GEN_DIR}/qt3dcore_qcomponent_wrapper.cpp
+${Qt3DCore_GEN_DIR}/qt3dcore_qcoreaspect_wrapper.cpp
 ${Qt3DCore_GEN_DIR}/qt3dcore_qcoresettings_wrapper.cpp
 ${Qt3DCore_GEN_DIR}/qt3dcore_qentity_wrapper.cpp
 ${Qt3DCore_GEN_DIR}/qt3dcore_qgeometry_wrapper.cpp
index cc17e246e24f8865e9bf263c4905dd28e346c04a..985c459b6f9c2cdfb4c8a506d2c1c05983edb18c 100644 (file)
@@ -4,7 +4,8 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.Qt3DCore">
+<typesystem package="PySide6.Qt3DCore"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
     <smart-pointer-type name="QSharedPointer" type="shared" getter="data"
                         reset-method="reset"
@@ -49,6 +50,7 @@
             </modify-argument>
           </modify-function>
         </object-type>
+        <object-type name="QCoreAspect"/>
         <object-type name="QCoreSettings"/>
         <object-type name="QGeometry"/>
         <object-type name="QGeometryView">
index cbda5068b2a17316ae8428c7d69ba7aff7793cc8..6f6f637fedbe601d7cdafc95575c680576a54b19 100644 (file)
@@ -60,12 +60,14 @@ set(Qt3DExtras_include_dirs
                      ${pyside6_SOURCE_DIR}
                      ${Qt${QT_MAJOR_VERSION}Core_INCLUDE_DIRS}
                      ${Qt${QT_MAJOR_VERSION}Gui_INCLUDE_DIRS}
+                     ${Qt${QT_MAJOR_VERSION}OpenGL_INCLUDE_DIRS}
                      ${Qt${QT_MAJOR_VERSION}3DCore_INCLUDE_DIRS}
                      ${Qt${QT_MAJOR_VERSION}3DRender_INCLUDE_DIRS}
                      ${Qt${QT_MAJOR_VERSION}3DExtras_INCLUDE_DIRS}
                      ${libpyside_SOURCE_DIR}
                      ${QtCore_GEN_DIR}
                      ${QtGui_GEN_DIR}
+                     ${QtOpenGL_GEN_DIR}
                      ${Qt3DCore_GEN_DIR}
                      ${Qt3DRender_GEN_DIR})
 
index 009dbdc9e151d483915ffdddc9902b603457bae1..d281ae15f36107622573db6bcfe5f5fc3f8b10be 100644 (file)
@@ -4,7 +4,8 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.Qt3DExtras">
+<typesystem package="PySide6.Qt3DExtras"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="Qt3DRender/typesystem_3drender.xml" generate="no"/>
     <namespace-type name="Qt3DExtras">
         <object-type name="QAbstractCameraController">
index 96160aeef2c56beb7814466ad9b29c4a02bd1436..fbdfc596148fda376dd48915783f5b207d1cb732 100644 (file)
@@ -4,7 +4,8 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.Qt3DInput">
+<typesystem package="PySide6.Qt3DInput"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="Qt3DCore/typesystem_3dcore.xml" generate="no"/>
     <namespace-type name="Qt3DInput">
         <object-type name="QAbstractActionInput"/>
index eef763e8339825983c42c92cbf2248e4e7600c32..60f36253407896ebef97f49f9b0e8be0ce5686a6 100644 (file)
@@ -4,7 +4,8 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.Qt3DLogic">
+<typesystem package="PySide6.Qt3DLogic"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="Qt3DCore/typesystem_3dcore.xml" generate="no"/>
     <namespace-type name="Qt3DLogic">
         <object-type name="QFrameAction"/>
index a4391fef0a8adbd56aacda48736af6b9355115e3..72f8593056019eeff37d18818b7b0f8daaa581c7 100644 (file)
@@ -3,6 +3,8 @@
 
 project(Qt3DRender)
 
+set(Qt3DRender_DROPPED_ENTRIES)
+
 set(Qt3DRender_SRC
 ${Qt3DRender_GEN_DIR}/qsharedpointer_propertyreaderinterface_wrapper.cpp
 ${Qt3DRender_GEN_DIR}/qsharedpointer_qtextureimagedata_wrapper.cpp
@@ -26,6 +28,7 @@ ${Qt3DRender_GEN_DIR}/qt3drender_qclipplane_wrapper.cpp
 ${Qt3DRender_GEN_DIR}/qt3drender_qcolormask_wrapper.cpp
 ${Qt3DRender_GEN_DIR}/qt3drender_qcomputecommand_wrapper.cpp
 ${Qt3DRender_GEN_DIR}/qt3drender_qcullface_wrapper.cpp
+${Qt3DRender_GEN_DIR}/qt3drender_qdebugoverlay_wrapper.cpp
 ${Qt3DRender_GEN_DIR}/qt3drender_qdepthrange_wrapper.cpp
 ${Qt3DRender_GEN_DIR}/qt3drender_qdepthtest_wrapper.cpp
 ${Qt3DRender_GEN_DIR}/qt3drender_qdirectionallight_wrapper.cpp
@@ -134,13 +137,16 @@ set(Qt3DRender_include_dirs
                      ${libpyside_SOURCE_DIR}
                      ${QtCore_GEN_DIR}
                      ${QtGui_GEN_DIR}
-                     ${QtOpenGL_GEN_DIR}
+
                      ${Qt3DCore_GEN_DIR})
 
 set(Qt3DRender_libraries pyside6
                      ${Qt${QT_MAJOR_VERSION}3DRender_LIBRARIES})
 
-set(Qt3DRender_deps Qt3DCore QtOpenGL)
+set(Qt3DRender_deps Qt3DCore)
+
+check_qt_opengl("3DRender" Qt3DRender_include_dirs Qt3DRender_deps
+                Qt3DRender_DROPPED_ENTRIES)
 
 create_pyside_module(NAME Qt3DRender
                      INCLUDE_DIRS Qt3DRender_include_dirs
@@ -148,4 +154,5 @@ create_pyside_module(NAME Qt3DRender
                      DEPS Qt3DRender_deps
                      TYPESYSTEM_PATH Qt3DRender_SOURCE_DIR
                      SOURCES Qt3DRender_SRC
-                     TYPESYSTEM_NAME ${Qt3DRender_BINARY_DIR}/typesystem_3drender.xml)
+                     TYPESYSTEM_NAME ${Qt3DRender_BINARY_DIR}/typesystem_3drender.xml
+                     DROPPED_ENTRIES Qt3DRender_DROPPED_ENTRIES)
index 3ebb09369a5faf7fc2cbe83630f9e62ddb551572..66fd709271929664bf7ddde1030afca09b8b6c10 100644 (file)
@@ -4,8 +4,14 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.Qt3DRender">
+<typesystem package="PySide6.Qt3DRender"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="Qt3DCore/typesystem_3dcore.xml" generate="no"/>
+    <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
+    <!-- PYSIDE-2610: QOpenGLTexture's enums are used -->
+    <?if !no_QtOpenGL?>
+    <load-typesystem name="QtOpenGL/typesystem_opengl.xml" generate="no"/>
+    <?endif?>
     <smart-pointer-type name="QSharedPointer" type="shared" getter="data"
                         reset-method="reset"
                         instantiations="Qt3DRender::PropertyReaderInterface=Qt3DRender::PropertyReaderInterfacePtr,Qt3DRender::QTextureImageData=Qt3DRender::QTextureImageDataPtr,Qt3DRender::QTextureImageDataGenerator=Qt3DRender::QTextureImageDataGeneratorPtr"/>
@@ -29,9 +35,7 @@
             <enum-type name="Target"/>
             <enum-type name="TextureFormat"/>
         </object-type>
-        <object-type name="QAbstractTextureImage">
-            <modify-function signature="QAbstractTextureImage(Qt3DCore::QNode*)" remove="all"/>
-        </object-type>
+        <object-type name="QAbstractTextureImage"/>
         <object-type name="QAlphaCoverage"/>
         <object-type name="QAlphaTest">
             <enum-type name="AlphaFunction"/>
@@ -64,6 +68,7 @@
         <object-type name="QCullFace">
             <enum-type name="CullingMode"/>
         </object-type>
+        <object-type name="QDebugOverlay"/>
         <object-type name="QDepthRange"/>
         <object-type name="QDepthTest">
             <enum-type name="DepthFunction"/>
             <enum-type name="Status"/>
         </object-type>
         <object-type name="QTextureImageData"/>
-        <object-type name="QTextureImageDataGenerator">
-            <modify-function signature="QTextureImageDataGenerator()" remove="all"/>
-        </object-type>
+        <object-type name="QTextureImageDataGenerator"/>
         <object-type name="QTextureLoader"/>
         <object-type name="QTextureRectangle"/>
         <object-type name="QTextureWrapMode">
index 3830ad887f953ee3fc6a41274aa05eee7555583b..60d1846d1912255fee047ce5966fe2fb25b7b01e 100644 (file)
@@ -20,19 +20,25 @@ __all__ = [
 def run(coro: typing.Optional[typing.Coroutine] = None,
         keep_running: bool = True,
         quit_qapp: bool = True, *,
-        debug: typing.Optional[bool] = None) -> None:
+        handle_sigint: bool = False,
+        debug: typing.Optional[bool] = None) -> typing.Any:
     """Run the QtAsyncio event loop."""
 
     # Event loop policies are expected to be deprecated with Python 3.13, with
     # subsequent removal in Python 3.15. At that point, part of the current
     # logic of the QAsyncioEventLoopPolicy constructor will have to be moved
     # here and/or to a loop factory class (to be provided as an argument to
-    # asyncio.run()), namely setting up the QCoreApplication and the SIGINT
-    # handler.
+    # asyncio.run()). In particular, this concerns the logic of setting up the
+    # QCoreApplication and the SIGINT handler.
     #
     # More details:
     # https://discuss.python.org/t/removing-the-asyncio-policy-system-asyncio-set-event-loop-policy-in-python-3-15/37553  # noqa: E501
-    asyncio.set_event_loop_policy(QAsyncioEventLoopPolicy(quit_qapp=quit_qapp))
+    default_policy = asyncio.get_event_loop_policy()
+    asyncio.set_event_loop_policy(
+        QAsyncioEventLoopPolicy(quit_qapp=quit_qapp, handle_sigint=handle_sigint))
+
+    ret = None
+    exc = None
 
     if keep_running:
         if coro:
@@ -40,8 +46,15 @@ def run(coro: typing.Optional[typing.Coroutine] = None,
         asyncio.get_event_loop().run_forever()
     else:
         if coro:
-            asyncio.run(coro, debug=debug)
+            ret = asyncio.run(coro, debug=debug)
         else:
-            raise RuntimeError(
+            exc = RuntimeError(
                 "QtAsyncio was set to keep running after the coroutine "
                 "finished, but no coroutine was provided.")
+
+    asyncio.set_event_loop_policy(default_policy)
+
+    if ret:
+        return ret
+    if exc:
+        raise exc
index aa89e984ef1816470684e9a5f1ee59576a781be7..86b89014a94e9796d779c976e7076828af73217c 100644 (file)
@@ -26,6 +26,19 @@ __all__ = [
 
 
 class QAsyncioExecutorWrapper(QObject):
+    """
+    Executors in asyncio allow running synchronous code in a separate thread or
+    process without blocking the event loop or interrupting the asynchronous
+    program flow. Callables are scheduled for execution by calling submit() or
+    map() on an executor object.
+
+    Executors require a bit of extra work for QtAsyncio, as we can't use
+    naked Python threads; instead, we must make sure that the thread created
+    by executor.submit() has an event loop. This is achieved by not submitting
+    the callable directly, but a small wrapper that attaches a QEventLoop to
+    the executor thread, and then creates a zero-delay singleshot timer to push
+    the actual callable for the executor into this new event loop.
+    """
 
     def __init__(self, func: typing.Callable, *args: typing.Tuple) -> None:
         super().__init__()
@@ -37,16 +50,21 @@ class QAsyncioExecutorWrapper(QObject):
 
     def _cb(self):
         try:
+            # Call the synchronous callable that we submitted with submit() or
+            # map().
             self._result = self._func(*self._args)
         except BaseException as e:
             self._exception = e
         self._loop.exit()
 
     def do(self):
-        # This creates a new event loop and dispatcher for the thread, if not already created.
+        # This creates a new event loop and dispatcher for the thread, if not
+        # already created.
         self._loop = QEventLoop()
         asyncio.events._set_running_loop(self._loop)
+
         QTimer.singleShot(0, self._loop, lambda: self._cb())
+
         self._loop.exec()
         if self._exception is not None:
             raise self._exception
@@ -57,9 +75,21 @@ class QAsyncioExecutorWrapper(QObject):
 
 
 class QAsyncioEventLoopPolicy(asyncio.AbstractEventLoopPolicy):
+    """
+    Event loop policies are expected to be deprecated with Python 3.13, with
+    subsequent removal in Python 3.15. At that point, part of the current
+    logic of the QAsyncioEventLoopPolicy constructor will have to be moved
+    to QtAsyncio.run() and/or to a loop factory class (to be provided as an
+    argument to asyncio.run()). In particular, this concerns the logic of
+    setting up the QCoreApplication and the SIGINT handler.
+
+    More details:
+    https://discuss.python.org/t/removing-the-asyncio-policy-system-asyncio-set-event-loop-policy-in-python-3-15/37553
+    """
     def __init__(self,
                  application: typing.Optional[QCoreApplication] = None,
-                 quit_qapp: bool = True) -> None:
+                 quit_qapp: bool = True,
+                 handle_sigint: bool = False) -> None:
         super().__init__()
         if application is None:
             if QCoreApplication.instance() is None:
@@ -67,14 +97,22 @@ class QAsyncioEventLoopPolicy(asyncio.AbstractEventLoopPolicy):
             else:
                 application = QCoreApplication.instance()
         self._application: QCoreApplication = application  # type: ignore[assignment]
+
+        # Configure whether the QCoreApplication at the core of QtAsyncio
+        # should be shut down when asyncio finishes. A special case where one
+        # would want to disable this is test suites that want to reuse a single
+        # QCoreApplication instance across all unit tests, which would fail if
+        # this instance is shut down every time.
         self._quit_qapp = quit_qapp
+
         self._event_loop: typing.Optional[asyncio.AbstractEventLoop] = None
 
-        signal.signal(signal.SIGINT, signal.SIG_DFL)
+        if handle_sigint:
+            signal.signal(signal.SIGINT, signal.SIG_DFL)
 
     def get_event_loop(self) -> asyncio.AbstractEventLoop:
         if self._event_loop is None:
-            self._event_loop = QAsyncioEventLoop(self._application)
+            self._event_loop = QAsyncioEventLoop(self._application, quit_qapp=self._quit_qapp)
         return self._event_loop
 
     def set_event_loop(self, loop: typing.Optional[asyncio.AbstractEventLoop]) -> None:
@@ -83,10 +121,10 @@ class QAsyncioEventLoopPolicy(asyncio.AbstractEventLoopPolicy):
     def new_event_loop(self) -> asyncio.AbstractEventLoop:
         return QAsyncioEventLoop(self._application, quit_qapp=self._quit_qapp)
 
-    def get_child_watcher(self) -> asyncio.AbstractChildWatcher:
+    def get_child_watcher(self) -> "asyncio.AbstractChildWatcher":
         raise DeprecationWarning("Child watchers are deprecated since Python 3.12")
 
-    def set_child_watcher(self, watcher: asyncio.AbstractChildWatcher) -> None:
+    def set_child_watcher(self, watcher: "asyncio.AbstractChildWatcher") -> None:
         raise DeprecationWarning("Child watchers are deprecated since Python 3.12")
 
 
@@ -97,6 +135,14 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject):
     """
 
     class ShutDownThread(QThread):
+        """
+        Used to shut down the default executor when calling
+        shutdown_default_executor(). As the executor is a ThreadPoolExecutor,
+        it must be shut down in a separate thread as all the threads from the
+        thread pool must join, which we want to do without blocking the event
+        loop.
+        """
+
         def __init__(self, future: futures.QAsyncioFuture, loop: "QAsyncioEventLoop") -> None:
             super().__init__()
             self._future = future
@@ -121,22 +167,48 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject):
         QObject.__init__(self)
 
         self._application: QCoreApplication = application
+
+        # Configure whether the QCoreApplication at the core of QtAsyncio
+        # should be shut down when asyncio finishes. A special case where one
+        # would want to disable this is test suites that want to reuse a single
+        # QCoreApplication instance across all unit tests, which would fail if
+        # this instance is shut down every time.
         self._quit_qapp = quit_qapp
+
         self._thread = QThread.currentThread()
 
         self._closed = False
 
+        # These two flags are used to determine whether the loop was stopped
+        # from inside the loop (i.e., coroutine or callback called stop()) or
+        # from outside the loop (i.e., the QApplication is being shut down, for
+        # example, by the user closing the window or by calling
+        # QApplication.quit()). The different cases can trigger slightly
+        # different behaviors (see the comments where the flags are used).
+        # There are two variables for this as in a third case the loop is still
+        # running and both flags are False.
         self._quit_from_inside = False
         self._quit_from_outside = False
 
+        # A set of all asynchronous generators that are currently running.
         self._asyncgens: typing.Set[collections.abc.AsyncGenerator] = set()
 
         # Starting with Python 3.11, this must be an instance of
         # ThreadPoolExecutor.
         self._default_executor = concurrent.futures.ThreadPoolExecutor()
 
+        # The exception handler, if set with set_exception_handler(). The
+        # exception handler is currently called in two places: One, if an
+        # asynchonrous generator raises an exception when closed, and two, if
+        # an exception is raised during the execution of a task. Currently, the
+        # default exception handler just prints the exception to the console.
         self._exception_handler: typing.Optional[typing.Callable] = self.default_exception_handler
+
+        # The task factory, if set with set_task_factory(). Otherwise, a new
+        # task is created with the QAsyncioTask constructor.
         self._task_factory: typing.Optional[typing.Callable] = None
+
+        # The future that is currently being awaited with run_until_complete().
         self._future_to_complete: typing.Optional[futures.QAsyncioFuture] = None
 
         self._debug = bool(os.getenv("PYTHONASYNCIODEBUG", False))
@@ -146,6 +218,10 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject):
     # Running and stopping the loop
 
     def _run_until_complete_cb(self, future: futures.QAsyncioFuture) -> None:
+        """
+        A callback that stops the loop when the future is done, used when
+        running the loop with run_until_complete().
+        """
         if not future.cancelled():
             if isinstance(future.exception(), (SystemExit, KeyboardInterrupt)):
                 return
@@ -186,16 +262,29 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject):
         asyncio.events._set_running_loop(None)
 
     def _about_to_quit_cb(self):
+        """ A callback for the aboutToQuit signal of the QCoreApplication. """
         if not self._quit_from_inside:
+            # If the aboutToQuit signal is emitted, the user is closing the
+            # application window or calling QApplication.quit(). In this case,
+            # we want to close the event loop, and we consider this a quit from
+            # outside the loop.
             self._quit_from_outside = True
+            self.close()
 
     def stop(self) -> None:
         if self._future_to_complete is not None:
             if self._future_to_complete.done():
                 self._future_to_complete = None
             else:
+                # Do not stop the loop if there is a future still being awaited
+                # with run_until_complete().
                 return
+
         self._quit_from_inside = True
+
+        # The user might want to keep the QApplication running after the event
+        # event loop finishes, which they can control with the quit_qapp
+        # argument.
         if self._quit_qapp:
             self._application.quit()
 
@@ -206,14 +295,12 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject):
         return self._closed
 
     def close(self) -> None:
-        if self.is_running():
+        if self.is_running() and not self._quit_from_outside:
             raise RuntimeError("Cannot close a running event loop")
         if self.is_closed():
             return
         if self._default_executor is not None:
             self._default_executor.shutdown(wait=False)
-        if self._quit_qapp:
-            self._application.shutdown()
         self._closed = True
 
     async def shutdown_asyncgens(self) -> None:
@@ -273,6 +360,8 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject):
     def call_soon_threadsafe(self, callback: typing.Callable, *args: typing.Any,
                              context:
                              typing.Optional[contextvars.Context] = None) -> asyncio.Handle:
+        if self.is_closed():
+            raise RuntimeError("Event loop is closed")
         if context is None:
             context = contextvars.copy_context()
         return self._call_soon_impl(callback, *args, context=context, is_threadsafe=True)
@@ -295,10 +384,9 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject):
                       callback: typing.Callable, *args: typing.Any,
                       context: typing.Optional[contextvars.Context] = None,
                       is_threadsafe: typing.Optional[bool] = False) -> asyncio.TimerHandle:
+        """ All call_at() and call_later() methods map to this method. """
         if not isinstance(when, (int, float)):
             raise TypeError("when must be an int or float")
-        if self.is_closed():
-            raise RuntimeError("Event loop is closed")
         return QAsyncioTimerHandle(when, callback, args, self, context, is_threadsafe=is_threadsafe)
 
     def call_at(self, when: typing.Union[int, float],
@@ -318,8 +406,6 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject):
                     coro: typing.Union[collections.abc.Generator, collections.abc.Coroutine],
                     *, name: typing.Optional[str] = None,
                     context: typing.Optional[contextvars.Context] = None) -> tasks.QAsyncioTask:
-        if self.is_closed():
-            raise RuntimeError("Event loop is closed")
         if self._task_factory is None:
             task = tasks.QAsyncioTask(coro, loop=self, name=name, context=context)
         else:
@@ -483,6 +569,13 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject):
             raise RuntimeError("Event loop is closed")
         if executor is None:
             executor = self._default_executor
+
+        # Executors require a bit of extra work for QtAsyncio, as we can't use
+        # naked Python threads; instead, we must make sure that the thread
+        # created by executor.submit() has an event loop. This is achieved by
+        # not submitting the callable directly, but a small wrapper that
+        # attaches a QEventLoop to the executor thread, and then pushes the
+        # actual callable for the executor into this new event loop.
         wrapper = QAsyncioExecutorWrapper(func, *args)
         return asyncio.futures.wrap_future(
             executor.submit(wrapper.do), loop=self
@@ -542,6 +635,12 @@ class QAsyncioEventLoop(asyncio.BaseEventLoop, QObject):
 
 
 class QAsyncioHandle():
+    """
+    The handle enqueues a callback to be executed by the event loop, and allows
+    for this callback to be cancelled before it is executed. This callback will
+    typically execute the step function for a task. This makes the handle one
+    of the main components of asyncio.
+    """
     class HandleState(enum.Enum):
         PENDING = enum.auto()
         CANCELLED = enum.auto()
@@ -561,18 +660,30 @@ class QAsyncioHandle():
         self._state = QAsyncioHandle.HandleState.PENDING
         self._start()
 
+    def _start(self) -> None:
+        self._schedule_event(self._timeout, lambda: self._cb())
+
     def _schedule_event(self, timeout: int, func: typing.Callable) -> None:
+        # Do not schedule events from asyncio when the app is quit from outside
+        # the event loop, as this would cause events to be enqueued after the
+        # event loop was destroyed.
         if not self._loop.is_closed() and not self._loop._quit_from_outside:
             if self._is_threadsafe:
+                # This singleShot overload will push func into self._loop
+                # instead of the current thread's loop. This allows scheduling
+                # a callback from a different thread, which is necessary for
+                # thread-safety.
+                # https://docs.python.org/3/library/asyncio-dev.html#asyncio-multithreading
                 QTimer.singleShot(timeout, self._loop, func)
             else:
                 QTimer.singleShot(timeout, func)
 
-    def _start(self) -> None:
-        self._schedule_event(self._timeout, lambda: self._cb())
-
     @Slot()
     def _cb(self) -> None:
+        """
+        A slot, enqueued into the event loop, that wraps around the actual
+        callback, typically the step function of a task.
+        """
         if self._state == QAsyncioHandle.HandleState.PENDING:
             if self._context is not None:
                 self._context.run(self._callback, *self._args)
@@ -582,7 +693,9 @@ class QAsyncioHandle():
 
     def cancel(self) -> None:
         if self._state == QAsyncioHandle.HandleState.PENDING:
-            # The old timer that was created in _start will still trigger but _cb won't do anything.
+            # The old timer that was created in _start will still trigger but
+            # _cb won't do anything, therefore the callback is effectively
+            # cancelled.
             self._state = QAsyncioHandle.HandleState.CANCELLED
 
     def cancelled(self) -> bool:
@@ -596,13 +709,16 @@ class QAsyncioTimerHandle(QAsyncioHandle, asyncio.TimerHandle):
         QAsyncioHandle.__init__(self, callback, args, loop, context, is_threadsafe)
 
         self._when = when
-        self._timeout = int(max(self._when - self._loop.time(), 0) * 1000)
+        time = self._loop.time()
+        self._timeout = round(max(self._when - time, 0) * 1000)
 
         QAsyncioHandle._start(self)
 
-    # Override this so that timer.start() is only called once at the end
-    # of the constructor for both QtHandle and QtTimerHandle.
     def _start(self) -> None:
+        """
+        Overridden so that timer.start() is only called once at the end of the
+        constructor for both QtHandle and QtTimerHandle.
+        """
         pass
 
     def when(self) -> float:
index 611bd5634a7b7401884e962a11da123a408364cb..cbb005fc92ee9d85e3d739212225501b75947cea 100644 (file)
@@ -36,10 +36,11 @@ class QAsyncioFuture():
         self._result: typing.Any = None
         self._exception: typing.Optional[BaseException] = None
 
-        self._callbacks: typing.List[typing.Callable] = list()
-
         self._cancel_message: typing.Optional[str] = None
 
+        # List of callbacks that are called when the future is done.
+        self._callbacks: typing.List[typing.Callable] = list()
+
     def __await__(self):
         if not self.done():
             self._asyncio_future_blocking = True
@@ -51,6 +52,7 @@ class QAsyncioFuture():
     __iter__ = __await__
 
     def _schedule_callbacks(self, context: typing.Optional[contextvars.Context] = None):
+        """ A future can optionally have callbacks that are called when the future is done. """
         for cb in self._callbacks:
             self._loop.call_soon(
                 cb, self, context=context if context else self._context)
index bc3d41a736ccdcdfc16d9ca6c37e1b816cfdd2e6..7edc15093284ca1734c94b77f654201984e4b1d8 100644 (file)
@@ -20,16 +20,22 @@ class QAsyncioTask(futures.QAsyncioFuture):
                  context: typing.Optional[contextvars.Context] = None) -> None:
         super().__init__(loop=loop, context=context)
 
-        self._coro = coro
+        self._coro = coro  # The coroutine for which this task was created.
         self._name = name if name else "QtTask"
 
+        # The task creates a handle for its coroutine. The handle enqueues the
+        # task's step function as its callback in the event loop.
         self._handle = self._loop.call_soon(self._step, context=self._context)
 
-        self._cancellation_requests = 0
-
+        # The task step function executes the coroutine until it finishes,
+        # raises an exception or returns a future. If a future was returned,
+        # the task will await its completion (or exception).
         self._future_to_await: typing.Optional[asyncio.Future] = None
+
+        self._cancelled = False
         self._cancel_message: typing.Optional[str] = None
 
+        # https://docs.python.org/3/library/asyncio-extending.html#task-lifetime-support
         asyncio._register_task(self)  # type: ignore[arg-type]
 
     def __repr__(self) -> str:
@@ -58,24 +64,39 @@ class QAsyncioTask(futures.QAsyncioFuture):
     def _step(self,
               exception_or_future: typing.Union[
                   BaseException, futures.QAsyncioFuture, None] = None) -> None:
+        """
+        The step function is the heart of a task. It is scheduled in the event
+        loop repeatedly, executing the coroutine "step" by "step" (i.e.,
+        iterating through the asynchronous generator) until it finishes with an
+        exception or successfully. Each step can optionally receive an
+        exception or a future as a result from a previous step to handle.
+        """
+
         if self.done():
             return
         result = None
         self._future_to_await = None
 
+        if asyncio.futures.isfuture(exception_or_future):
+            try:
+                exception_or_future.result()
+            except BaseException as e:
+                exception_or_future = e
+
         try:
             asyncio._enter_task(self._loop, self)  # type: ignore[arg-type]
-            if exception_or_future is None:
-                result = self._coro.send(None)
-            elif asyncio.futures.isfuture(exception_or_future):
-                try:
-                    exception_or_future.result()
-                except BaseException as e:
-                    result = self._coro.throw(e)
-                else:
-                    result = self._coro.send(None)
-            elif isinstance(exception_or_future, BaseException):
+
+            # It is at this point that the coroutine is resumed for the current
+            # step (i.e. asynchronous generator iteration). It will now be
+            # executed until it yields (and potentially returns a future),
+            # raises an exception, is cancelled, or finishes successfully.
+
+            if isinstance(exception_or_future, BaseException):
+                # If the coroutine doesn't handle this exception, it propagates
+                # to the caller.
                 result = self._coro.throw(exception_or_future)
+            else:
+                result = self._coro.send(None)
         except StopIteration as e:
             self._state = futures.QAsyncioFuture.FutureState.DONE_WITH_RESULT
             self._result = e.value
@@ -87,16 +108,32 @@ class QAsyncioTask(futures.QAsyncioFuture):
             self._exception = e
         else:
             if asyncio.futures.isfuture(result):
+                # If the coroutine yields a future, the task will await its
+                # completion, and at that point the step function will be
+                # called again.
                 result.add_done_callback(
                     self._step, context=self._context)  # type: ignore[arg-type]
                 self._future_to_await = result
+                if self._cancelled:
+                    # If the task was cancelled, then a new future should be
+                    # cancelled as well. Otherwise, in some scenarios like
+                    # a loop inside the task and with bad timing, if the new
+                    # future is not cancelled, the task would continue running
+                    # in this loop despite having been cancelled. This bad
+                    # timing can occur especially if the first future finishes
+                    # very quickly.
+                    self._future_to_await.cancel(self._cancel_message)
             elif result is None:
+                # If no future was yielded, we schedule the step function again
+                # without any arguments.
                 self._loop.call_soon(self._step, context=self._context)
             else:
+                # This is not supposed to happen.
                 exception = RuntimeError(f"Bad task result: {result}")
                 self._loop.call_soon(self._step, exception, context=self._context)
         finally:
             asyncio._leave_task(self._loop, self)  # type: ignore[arg-type]
+
             if self._exception:
                 self._loop.call_exception_handler({
                     "message": (str(self._exception) if self._exception
@@ -108,8 +145,11 @@ class QAsyncioTask(futures.QAsyncioFuture):
                                if asyncio.futures.isfuture(exception_or_future)
                                else None)
                 })
+
             if self.done():
                 self._schedule_callbacks()
+
+                # https://docs.python.org/3/library/asyncio-extending.html#task-lifetime-support
                 asyncio._unregister_task(self)  # type: ignore[arg-type]
 
     def get_stack(self, *, limit=None) -> typing.List[typing.Any]:
@@ -135,7 +175,10 @@ class QAsyncioTask(futures.QAsyncioFuture):
         self._cancel_message = msg
         self._handle.cancel()
         if self._future_to_await is not None:
+            # A task that is awaiting a future must also cancel this future in
+            # order for the cancellation to be successful.
             self._future_to_await.cancel(msg)
+        self._cancelled = True
         return True
 
     def uncancel(self) -> None:
index 4c570f87aec2dfd0bd921a91c89e2a106237174a..4d1cbe91c8169c5b127ab1466748ff27e90b555b 100644 (file)
@@ -4,7 +4,8 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.QtAxContainer">
+<typesystem package="PySide6.QtAxContainer"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
     <rejection class="*" function-name="connectNotify"/>
     <rejection class="*" function-name="queryInterface"/>
index 737305bbdeec6493cbaac3d76c279db03b53c76c..a3687b6b028f20cb3953c902f284839452c0f87f 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2021 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtBluetooth">
+<typesystem package="PySide6.QtBluetooth"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <namespace-type name="QBluetooth">
         <enum-type name="AttAccessConstraint" flags="AttAccessConstraints"/>
index f7a4d3cc6dcdfcd6ff198c79a63fb5bd6ee8cc73..20126fdee2d7fe870f298671f80027f66895e400 100644 (file)
@@ -73,10 +73,7 @@ set(QtCharts_include_dirs ${QtCharts_SOURCE_DIR}
                           ${QtWidgets_GEN_DIR})
 
 set(QtCharts_libraries    pyside6
-                          ${Qt${QT_MAJOR_VERSION}Charts_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES})
+                          ${Qt${QT_MAJOR_VERSION}Charts_LIBRARIES})
 
 set(QtCharts_deps QtCore QtGui QtWidgets)
 
index a9cd73173330d23191367fa067bda48fef29d0af..d4337df8e09e448607bd6a4fc36859255f066297 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2021 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtCharts">
+<typesystem package="PySide6.QtCharts"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
   <!-- PYSIDE-1101 Removing inherited method to avoid argument conflict
   on the QChart::scroll overload -->
index c32ff17fd41b82c40b50d5f4ea470c23d8041b31..134e44ed9032430862467baa6450d60ed7c6b9ff 100644 (file)
@@ -18,12 +18,11 @@ set(QtConcurrent_include_dirs   ${QtConcurrent_SOURCE_DIR}
                                 ${Qt${QT_MAJOR_VERSION}Core_INCLUDE_DIRS}
                                 ${Qt${QT_MAJOR_VERSION}Concurrent_INCLUDE_DIRS}
                                 ${libpyside_SOURCE_DIR}
-                                ${QtCore_GEN_DIR}
-                                )
-set(QtConcurrent_libraries  pyside6
-                            ${QtConcurrent_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                            )
+                                ${QtCore_GEN_DIR})
+
+set(QtConcurrent_libraries pyside6
+                           ${Qt${QT_MAJOR_VERSION}Concurrent_LIBRARIES})
+
 set(QtConcurrent_deps QtCore)
 
 create_pyside_module(NAME QtConcurrent
index 84213a61f0eed276cdb5c250e477a22199393d33..1892793b9f6d5f59022bf3e97252e84402c96052 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtConcurrent">
+<typesystem package="PySide6.QtConcurrent"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
 
   <!-- Qt5: this is currently the minimum possible QtConcurrent support, by just extracting
index e2e314d3f09bfaea0714168ef683993c89aa46a9..f3e4be0f9dfa19cb3ac33429b970e5efe254f58c 100644 (file)
@@ -3,12 +3,16 @@
 
 project(QtCore)
 
+set(CMAKE_AUTOMOC ON)
+
 set(QtCore_DROPPED_ENTRIES )
 
 set(QtCore_static_sources
     "${QtCore_SOURCE_DIR}/glue/qeasingcurve_glue.cpp"
     "${QtCore_SOURCE_DIR}/glue/core_snippets.cpp"
     "${QtCore_SOURCE_DIR}/glue/qtcorehelper.cpp"
+    "${QtCore_SOURCE_DIR}/glue/qiopipe.cpp"
+    "${pyside6_SOURCE_DIR}/qiopipe.h"
 )
 
 if(ENABLE_WIN)
@@ -163,6 +167,7 @@ ${QtCore_GEN_DIR}/qsystemsemaphore_wrapper.cpp
 ${QtCore_GEN_DIR}/qt_wrapper.cpp
 ${QtCore_GEN_DIR}/qtcorehelper_qgenericargumentholder_wrapper.cpp
 ${QtCore_GEN_DIR}/qtcorehelper_qgenericreturnargumentholder_wrapper.cpp
+${QtCore_GEN_DIR}/qtcorehelper_qiopipe_wrapper.cpp
 ${QtCore_GEN_DIR}/qtcorehelper_qmutexlocker_wrapper.cpp
 ${QtCore_GEN_DIR}/qtemporarydir_wrapper.cpp
 ${QtCore_GEN_DIR}/qtemporaryfile_wrapper.cpp
@@ -242,6 +247,7 @@ set(QtCore_include_dirs ${QtCore_SOURCE_DIR}
                         )
 set(QtCore_libraries  pyside6
                       ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
+                      Qt::CorePrivate
                       )
 
 create_pyside_module(NAME QtCore
@@ -255,4 +261,31 @@ create_pyside_module(NAME QtCore
                      DROPPED_ENTRIES QtCore_DROPPED_ENTRIES
                      )
 
-install(FILES ${pyside6_SOURCE_DIR}/qtcorehelper.h DESTINATION include/PySide6/QtCore/)
+# Note: The permission API for Apple platforms only works if the Python application is packaged
+# with pyside6-deploy (uses Nuitka). Read "Notes for Developers" in Qt for Python documentation
+# for more information
+#
+# For Apple platforms, the Qt permission API implementations are in small static libraries.
+# In Qt C++, the application is linked directly to these static libraries during the build when
+# linking to the QtCore module as a post processing CMake step.
+# Being static plugins makes it difficult to add these plugins during Nuitka packaging step.
+# Thus, we link the static plugins to QtCore.abi3.so. However, to request the permissions
+# it is still required to have the necessary Information Property keys eg: NSCameraUsageDescription
+# in the Info.plist of the application bundle which Nuitka creates.
+if (APPLE)
+    set(permissions Camera Microphone Bluetooth Contacts Calendar)
+    foreach(permission IN LISTS permissions)
+        set(permission_plugin_name "QDarwin${permission}PermissionPlugin")
+        set(permission_plugin "${QT_CMAKE_EXPORT_NAMESPACE}::${permission_plugin_name}")
+        # Setting this property is necessary for Camera and Microphone. Otherwise it won't append
+        # the linker flags like -Wl,-u,_QDarwinMicrophonePermissionRequest which are required to
+        # link to qdarwinpermissionplugin_microphone_request.mm.o and find symbols like
+        # QDarwinMicrosphonePermissionHandler which handles requesting the actual permission
+        set_target_properties(QtCore PROPERTIES "_qt_has_${permission_plugin_name}_usage_description" TRUE)
+        # importing the plugin
+        qt6_import_plugins(QtCore INCLUDE ${permission_plugin})
+    endforeach()
+endif()
+
+install(FILES ${pyside6_SOURCE_DIR}/qtcorehelper.h ${pyside6_SOURCE_DIR}/qiopipe.h
+        DESTINATION include/PySide6/QtCore/)
index 55a49bb880608700a2868b0747a983ba79afaa4f..8383b9ae4576604b10788a36ce70e1b9d96038db 100644 (file)
@@ -1 +1,2 @@
 #include <qtcorehelper.h>
+#include <qiopipe.h>
index 4266e868c5dcecaa0e91642894a9c27b4dca793b..f6acf9d60703fcc9cad76a621fc84e7b21dbcb78 100644 (file)
@@ -340,9 +340,7 @@ PyObject *invokeMetaMethodWithReturn(const InvokeMetaMethodFuncWithReturn &f,
                               a6.toGenericArgument(), a7.toGenericArgument(), a8.toGenericArgument(),
                               a9.toGenericArgument());
     PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS
-    if (!callResult) {
-        PyErr_SetString(PyExc_RuntimeError, "QMetaMethod invocation failed.");
-        return nullptr;
-    }
+    if (!callResult)
+        return PyErr_Format(PyExc_RuntimeError, "QMetaMethod invocation failed.");
     return convertGenericReturnArgument(r.data(), r.metaType());
 }
index eeeed98e760e3970fbb4afbc42a2d5877c583e15..11e84b2914816f747001a76109b419223e3d4a60 100644 (file)
@@ -19,10 +19,12 @@ QT_FORWARD_DECLARE_CLASS(QObject)
 QT_FORWARD_DECLARE_CLASS(QRegularExpression)
 QT_FORWARD_DECLARE_CLASS(QVariant);
 
+QT_BEGIN_NAMESPACE
 namespace QtCoreHelper {
 class QGenericArgumentHolder;
 class QGenericReturnArgumentHolder;
 }
+QT_END_NAMESPACE
 
 // Helpers for QVariant conversion
 
diff --git a/sources/pyside6/PySide6/QtCore/glue/qiopipe.cpp b/sources/pyside6/PySide6/QtCore/glue/qiopipe.cpp
new file mode 100644 (file)
index 0000000..6799c0f
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qiopipe.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qpointer.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtCoreHelper
+{
+
+class QPipeEndPoint : public QIODevice
+{
+    Q_OBJECT
+
+public:
+    bool isSequential() const override;
+    qint64 bytesAvailable() const override;
+
+    void setRemoteEndPoint(QPipeEndPoint *other);
+
+protected:
+    qint64 readData(char *data, qint64 maxlen) override;
+    qint64 writeData(const char *data, qint64 len) override;
+
+private:
+    QByteArray m_buffer;
+    QPointer<QPipeEndPoint> m_remoteEndPoint;
+};
+
+class QIOPipePrivate final : public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(QIOPipe)
+public:
+    QIOPipePrivate();
+    ~QIOPipePrivate() {};
+
+    std::unique_ptr<QPipeEndPoint> end1;
+    std::unique_ptr<QPipeEndPoint> end2;
+};
+
+QIOPipe::QIOPipe(QObject *parent) : QObject(*(new QIOPipePrivate()), parent) { }
+
+bool QIOPipe::open(QIODevice::OpenMode mode)
+{
+    Q_D(QIOPipe);
+
+    if (!d->end1->open(mode))
+        return false;
+    switch (mode & QIODevice::ReadWrite) {
+    case QIODevice::WriteOnly:
+    case QIODevice::ReadOnly:
+        return d->end2->open(mode ^ QIODevice::ReadWrite);
+    default:
+        return d->end2->open(mode);
+    }
+}
+
+QIODevice *QIOPipe::end1() const
+{
+    Q_D(const QIOPipe);
+    return d->end1.get();
+}
+
+QIODevice *QIOPipe::end2() const
+{
+    Q_D(const QIOPipe);
+    return d->end2.get();
+}
+
+QIOPipePrivate::QIOPipePrivate() : end1(std::make_unique<QPipeEndPoint>()),
+                                   end2(std::make_unique<QPipeEndPoint>())
+{
+    end1->setRemoteEndPoint(end2.get());
+    end2->setRemoteEndPoint(end1.get());
+}
+
+bool QPipeEndPoint::isSequential() const
+{
+    return true;
+}
+
+qint64 QPipeEndPoint::bytesAvailable() const
+{
+    return m_buffer.size() + QIODevice::bytesAvailable();
+}
+
+void QPipeEndPoint::setRemoteEndPoint(QPipeEndPoint *other)
+{
+    m_remoteEndPoint = other;
+}
+
+qint64 QPipeEndPoint::readData(char *data, qint64 maxlen)
+{
+    maxlen = qMin(maxlen, static_cast<qint64>(m_buffer.size()));
+    if (maxlen <= 0)
+        return 0;
+
+    Q_ASSERT(maxlen > 0);
+    memcpy(data, m_buffer.data(), static_cast<size_t>(maxlen));
+    m_buffer = m_buffer.mid(maxlen);
+    return maxlen;
+}
+
+qint64 QPipeEndPoint::writeData(const char *data, qint64 len)
+{
+    if (!m_remoteEndPoint)
+        return -1;
+
+    if (len <= 0)
+        return 0;
+
+    QByteArray &buffer = m_remoteEndPoint->m_buffer;
+    const qint64 prevLen = buffer.size();
+    Q_ASSERT(prevLen >= 0);
+    len = qMin(len, std::numeric_limits<int>::max() - prevLen);
+
+    if (len == 0)
+        return 0;
+
+    Q_ASSERT(len > 0);
+    Q_ASSERT(prevLen + len > 0);
+    Q_ASSERT(prevLen + len <= std::numeric_limits<int>::max());
+
+    buffer.resize(prevLen + len);
+    memcpy(buffer.data() + prevLen, data, static_cast<size_t>(len));
+    Q_EMIT bytesWritten(len);
+    Q_EMIT m_remoteEndPoint->readyRead();
+    return len;
+}
+
+} // namespace QtCoreHelper
+
+QT_END_NAMESPACE
+
+#include "qiopipe.moc"
index 2517808c6c2e0b4362f8b5b2ff0d3b554f2561f7..948c0ce5c86b4fac9628e17c4450f378374aaebc 100644 (file)
@@ -5,6 +5,8 @@
 
 #include <QtCore/qdebug.h>
 
+QT_BEGIN_NAMESPACE
+
 namespace QtCoreHelper {
 
 // Data classes for the generic argument data classes. The argument is freed
@@ -102,3 +104,5 @@ const void *QGenericReturnArgumentHolder::data() const
 }
 
 } // namespace QtCoreHelper
+
+QT_END_NAMESPACE
index 7dd664294e845251b1adca0c499b9edcac21dbe7..885b538740d02a7947c8682bbd8dd791583c7b0f 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtCore">
+<typesystem package="PySide6.QtCore"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <?if windows?>
     <load-typesystem name="QtCore/typesystem_core_win.xml" generate="yes"/>
     <?endif?>
index 5168373fd650c0bde85b49af79d3faad1e6294d5..19a50848ff11ed2cc4dda9657458575e75d8f73b 100644 (file)
             <modify-argument index="return" pyi-type="str"/>
         </modify-function>
     </function>
-    <function signature="qCompress(const uchar*,qsizetype,int)"/>
-    <function signature="qCompress(const QByteArray&amp;,int)"/>
-    <function signature="qUncompress(const uchar*,qsizetype)"/>
-    <function signature="qUncompress(const QByteArray&amp;)"/>
-    <function signature="qFormatLogMessage(QtMsgType,const QMessageLogContext&amp;,const QString&amp;)"/>
-    <function signature="qSetMessagePattern(const QString&amp;)"/>
+    <!-- Move PyBuffer overload to front to avoid conversion PyBuffer->QByteArray -->
+    <function signature="qCompress(const uchar*,qsizetype,int)" overload-number="0">
+        <modify-function>
+            <modify-argument index="1">
+                <replace-type modified-type="PyBuffer"/>
+            </modify-argument>
+            <inject-code file="../glue/qtcore.cpp" snippet="qcompress-buffer"/>
+        </modify-function>
+    </function>
+    <function signature="qCompress(const QByteArray&amp;,int)" overload-number="1"/>
+    <!-- Move PyBuffer overload to front to avoid conversion PyBuffer->QByteArray -->
+    <function signature="qUncompress(const uchar*,qsizetype)" overload-number="0">
+        <modify-function>
+            <modify-argument index="1">
+                <replace-type modified-type="PyBuffer"/>
+            </modify-argument>
+            <inject-code file="../glue/qtcore.cpp" snippet="quncompress-buffer"/>
+        </modify-function>
+    </function>
+    <function signature="qUncompress(const QByteArray&amp;)"  overload-number="1"/>
+    <function signature="qFormatLogMessage(QtMsgType,const QMessageLogContext&amp;,const QString&amp;)"
+              doc-file="qtlogging"/>
+    <function signature="qSetMessagePattern(const QString&amp;)" doc-file="qtlogging"/>
 
     <inject-code class="native" position="beginning" file="../glue/qtcore.cpp" snippet="include-pyside"/>
     <inject-code class="native" position="beginning" file="../glue/qtcore.cpp"
                  snippet="qarg_helper"/>
+    <inject-code class="native" position="beginning" file="../glue/qtcore.cpp"
+                 snippet="darwin_permission_plugin"/>
 
     <add-function signature="qDebug(const char*)">
         <inject-code file="../glue/qtcore.cpp" snippet="use-stream-for-format-security"/>
 
   <!-- From Qt4.6 ^^^ -->
 
-  <enum-type name="QtMsgType"/>
-  <enum-type name="QCborSimpleType"/>
-  <enum-type name="QCborKnownTags"/>
-  <enum-type name="QCborTag"/>
+  <enum-type name="QtMsgType" doc-file="qtlogging"/>
+  <enum-type name="QCborSimpleType" doc-file="qtcborcommon"/>
+  <enum-type name="QCborKnownTags" doc-file="qtcborcommon"/>
+  <enum-type name="QCborTag" doc-file="qtcborcommon"/>
 
   <primitive-type name="qint8"/>
   <primitive-type name="qint16"/>
     </conversion-rule>
   </primitive-type>
 
+  <primitive-type name="QLatin1String" target-lang-api-name="PyUnicode">
+    <include file-name="QtCore/qlatin1stringview.h" location="global"/>
+    <conversion-rule>
+        <native-to-target file="../glue/qtcore.cpp" snippet="return-pyunicode-from-qlatin1string"/>
+        <target-to-native>
+            <add-conversion type="PyString" check="qLatin1StringCheck(%in)"
+                            file="../glue/qtcore.cpp" snippet="conversion-pystring-qlatin1string"/>
+        </target-to-native>
+    </conversion-rule>
+  </primitive-type>
+
   <primitive-type name="QAnyStringView" target-lang-api-name="PyUnicode" view-on="QString">
     <include file-name="QAnyStringView" location="global"/>
     <conversion-rule>
   </primitive-type>
 
   <primitive-type name="QVariant" target-lang-api-name="PyObject">
+    <extra-includes>
+        <include file-name="optional" location="global"/>
+    </extra-includes>
     <conversion-rule>
         <native-to-target file="../glue/qtcore.cpp" snippet="return-qvariant"/>
         <target-to-native>
     <enum-type name="WindowType" python-type="IntFlag" flags="WindowFlags"/>
     <enum-type name="CursorMoveStyle" since="4.8" revision="4800"/>
 
+    <inject-code class="target" position="end" file="../glue/qtcore.cpp"
+                 snippet="qt-modifier"/>
   </namespace-type>
 
   <add-function signature="QEnum(PyObject*)" return-type="PyObject*">
   <inject-code class="target" position="end" file="../glue/qtcore.cpp" snippet="qt-pysideinit"/>
 
   <inject-code class="native" position="beginning" file="../glue/qtcore.cpp" snippet="qt-messagehandler"/>
+  <inject-code class="native" position="beginning" file="../glue/qtcore.cpp"
+               snippet="qlatin1string-check"/>
   <add-function signature="qInstallMessageHandler(PyObject)" return-type="PyObject">
     <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qt-installmessagehandler"/>
   </add-function>
     <enum-type name="ClockType" since="4.7"/>
   </value-type>
 
-  <object-type name="QAbstractTableModel" polymorphic-id-expression="qobject_cast&lt;QAbstractTableModel*&gt;(%1)">
+  <object-type name="QAbstractTableModel"
+               polymorphic-id-expression="qobject_cast&lt;QAbstractTableModel*&gt;(%B)">
     <extra-includes>
       <include file-name="QStringList" location="global"/>
       <include file-name="QSize" location="global"/>
       <enum-type name="System"/>
       <enum-type identified-by-value="Unspecified"/>
   </value-type>
-  <value-type name="QDate" hash-function="PySide::hash" >
-    <extra-includes>
-      <include file-name="pysideqhash.h" location="global"/>
-    </extra-includes>
+  <value-type name="QDate">
     <inject-code class="native" position="beginning" file="../glue/qtcore.cpp"
                  snippet="core-snippets-p-h"/>
     <conversion-rule>
         <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qdate-weeknumber"/>
     </modify-function>
   </value-type>
-  <value-type name="QDateTime" hash-function="PySide::hash">
-    <extra-includes>
-      <include file-name="pysideqhash.h" location="global"/>
-    </extra-includes>
+  <value-type name="QDateTime">
     <inject-code class="native" position="beginning" file="../glue/qtcore.cpp"
                  snippet="core-snippets-p-h"/>
     <enum-type name="YearRange"/>
+    <enum-type name="TransitionResolution" since="6.7"/>
     <conversion-rule>
         <target-to-native>
             <add-conversion type="Py_None" file="../glue/qtcore.cpp" snippet="conversion-pynone"/>
       <configuration condition="QT_CONFIG(permissions)"/>
   </value-type>
 
-  <value-type name="QPoint" hash-function="PySide::hash">
-    <extra-includes>
-      <include file-name="pysideqhash.h" location="global"/>
-    </extra-includes>
+  <value-type name="QPoint">
     <add-function signature="__repr__" return-type="PyObject*">
         <inject-code class="target" position="beginning">
             <insert-template name="repr_code">
             </insert-template>
         </inject-code>
     </add-function>
-    <inject-code class="native" position="beginning" file="../glue/qtcore.cpp" snippet="qpoint"/>
 
     <add-function signature="toTuple" return-type="PyObject*">
         <inject-code class="target" position="beginning">
     <modify-function signature="ry()" remove="all"/>
     <!--### -->
   </value-type>
-  <value-type name="QRect" hash-function="PySide::hash">
-    <extra-includes>
-      <include file-name="pysideqhash.h" location="global"/>
-    </extra-includes>
+  <value-type name="QRect">
     <add-function signature="__repr__" return-type="PyObject*">
         <inject-code class="target" position="beginning">
             <insert-template name="repr_code">
             </insert-template>
         </inject-code>
     </add-function>
-    <inject-code class="native" position="beginning" file="../glue/qtcore.cpp" snippet="qrect"/>
 
     <modify-function signature="getCoords(int*,int*,int*,int*)const">
         <modify-argument index="return">
         </inject-code>
     </modify-function>
   </value-type>
-  <value-type name="QSize" hash-function="PySide::hash">
-    <extra-includes>
-      <include file-name="pysideqhash.h" location="global"/>
-    </extra-includes>
+  <value-type name="QSize">
     <add-function signature="__repr__" return-type="PyObject*">
         <inject-code class="target" position="beginning">
             <insert-template name="repr_code">
             </insert-template>
         </inject-code>
     </add-function>
-    <inject-code class="native" position="beginning" file="../glue/qtcore.cpp" snippet="qsize"/>
 
     <add-function signature="toTuple" return-type="PyObject*">
         <inject-code class="target" position="beginning">
     <!--### -->
   </value-type>
 
-  <value-type name="QTime" hash-function="PySide::hash">
-    <extra-includes>
-      <include file-name="pysideqhash.h" location="global"/>
-    </extra-includes>
+  <value-type name="QTime">
     <inject-code class="native" position="beginning" file="../glue/qtcore.cpp"
                  snippet="core-snippets-p-h"/>
     <conversion-rule>
      qRegisterMetaType&lt;QList&lt;QPersistentModelIndex&gt; &gt;("QList_QPersistentModelIndex");
    </inject-code>
     <modify-function signature="internalPointer()const">
+        <modify-argument index="return" pyi-type="Any"/>
         <inject-code class="target" position="beginning">
             <insert-template name="return_internal_pointer" />
         </inject-code>
   </object-type>
 
   <value-type name="QLocale">
+    <enum-type name="TagSeparator" since="6.7"/>
     <enum-type name="Country"/>
     <enum-type name="DataSizeFormat" flags="DataSizeFormats"/>
     <enum-type name="FloatingPointPrecisionOption" python-type="IntEnum"/>
             <rename to="format"/>
         </modify-argument>
     </modify-function>
-    <modify-function signature="toDate(QString,QLocale::FormatType)const">
+    <modify-function signature="toDate(QString,QLocale::FormatType,int)const">
         <modify-argument index="2">
             <rename to="format"/>
         </modify-argument>
     </modify-function>
+    <modify-function signature="^toDate(Time)?\(QString,[^,]+,int\)const$">
+        <modify-argument index="3">
+            <replace-default-expression with="1900"/> <!-- private FirstTwoDigitYear -->
+        </modify-argument>
+    </modify-function>
+    <modify-function signature="^toDate(Time)?\(QString,[^,]+,QCalendar,int\)const$">
+        <modify-argument index="4">
+            <replace-default-expression with="1900"/> <!-- private FirstTwoDigitYear -->
+        </modify-argument>
+    </modify-function>
     <modify-function signature="toUInt(QString,bool*)const">
         <modify-argument index="2">
             <remove-argument />
       <modify-function signature="removeStaleLockFile()" allow-thread="yes"/>
       <modify-function signature="tryLock(int)" allow-thread="yes"/>
       <modify-function signature="unlock()" allow-thread="yes"/>
+      <modify-function signature="getLockInfo(qint64*,QString*,QString*)const">
+          <modify-argument index="return" pyi-type="Tuple[int, str, str]">
+              <replace-type modified-type="(int, str, str)"/>
+          </modify-argument>
+          <modify-argument index="1"><remove-argument/></modify-argument>
+          <modify-argument index="2"><remove-argument/></modify-argument>
+          <modify-argument index="3"><remove-argument/></modify-argument>
+          <inject-code class="target" position="beginning"
+                       file="../glue/qtcore.cpp" snippet="qlockfile-getlockinfo"/>
+      </modify-function>
   </object-type>
   <object-type name="QMessageAuthenticationCode"/>
   <object-type name="QSignalBlocker">
     <add-function signature="operator==(const QItemSelection&amp;)" return-type="bool"/>
     <add-function signature="operator!=(const QItemSelection&amp;)" return-type="bool"/>
     <!-- For some reason, the empty selection is not seen. Maybe related to the new [default]
-         tag in Qt6? -->
-    <declare-function signature="QItemSelection()" return-type="QItemSelection" />
+         tag in Qt6?
+         PYSIDE-2756: The return-type attribute is unnecessary -->
+    <declare-function signature="QItemSelection()"/>
     <!-- The __add__ function creates a result list, instead of using the inherited type.
          Fixed by adding with the correct type. -->
     <add-function signature="operator+(QItemSelection)" return-type="QItemSelection">
 
   <value-type name="QItemSelectionRange">
   </value-type>
-  <object-type name="QAbstractProxyModel" polymorphic-id-expression="qobject_cast&lt;QAbstractProxyModel*&gt;(%1)">
+  <object-type name="QAbstractProxyModel"
+               polymorphic-id-expression="qobject_cast&lt;QAbstractProxyModel*&gt;(%B)">
     <extra-includes>
       <include file-name="QItemSelection" location="global"/>
       <include file-name="QStringList" location="global"/>
         <reference-count action="set"/>
       </modify-argument>
     </modify-function>
-
+    <!-- FIXME PYSIDE 7: Remove this (QT6_DECL_NEW_OVERLOAD_TAIL) -->
+    <modify-function signature="^moveToThread\(.*\)" remove="all"/>
+    <declare-function signature="moveToThread(QThread*)" return-type="bool"/>
     <modify-function signature="deleteLater()">
       <modify-argument index="this">
         <define-ownership owner="c++"/>
       </modify-argument>
       <modify-argument index="1" pyi-type="Optional[PySide6.QtCore.QObject]"/>
     </modify-function>
-    <modify-function signature="connect(const QObject*,const char*,const char*,Qt::ConnectionType)const">
+    <!-- Manual overload order fixes PYSIDE-2627
+
+         The addition of the qobject-connect-4-context overload resulted in an
+         automatic overload ordering that prevented the right overload from
+         ever being called if the callable was a QObject. Set a manual order to
+         fix this. -->
+    <modify-function signature="connect(const QObject*,const char*,const char*,Qt::ConnectionType)const"
+                     overload-number="0">
         <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qobject-connect-1"/>
     </modify-function>
     <!-- static version -->
-    <modify-function signature="connect(const QObject*,QMetaMethod,const QObject*,QMetaMethod,Qt::ConnectionType)">
+    <modify-function signature="connect(const QObject*,QMetaMethod,const QObject*,QMetaMethod,Qt::ConnectionType)"
+                     overload-number="1">
         <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qobject-connect-2"/>
     </modify-function>
-    <modify-function signature="connect(const QObject*,const char*,const QObject*,const char*,Qt::ConnectionType)">
+    <modify-function signature="connect(const QObject*,const char*,const QObject*,const char*,Qt::ConnectionType)"
+                     overload-number="2">
         <modify-argument index="5">
             <rename to="type"/>
         </modify-argument>
     </modify-function>
     <inject-code class="native" position="beginning" file="../glue/qtcore.cpp" snippet="qobject-connect"/>
     <add-function signature="connect(const QObject*@sender@,const char*@signal@,PyCallable*@functor@,Qt::ConnectionType@type@=Qt::AutoConnection)"
-                  return-type="QMetaObject::Connection" static="yes">
+                  return-type="QMetaObject::Connection" static="yes" overload-number="3">
         <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qobject-connect-4"/>
     </add-function>
     <add-function signature="connect(const QObject*@sender@,const char*@signal@,const QObject*@context@,PyCallable*@functor@,Qt::ConnectionType@type@=Qt::AutoConnection)"
-                  return-type="QMetaObject::Connection" static="yes">
+                  return-type="QMetaObject::Connection" static="yes" overload-number="4">
         <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qobject-connect-4-context"/>
     </add-function>
     <!-- static version -->
     <add-function signature="connect(const char*@signal@,PyCallable*@functor@,Qt::ConnectionType@type@=Qt::AutoConnection)"
-                  return-type="QMetaObject::Connection">
+                  return-type="QMetaObject::Connection" overload-number="5">
         <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qobject-connect-5"/>
     </add-function>
     <add-function signature="connect(const char*@signal@,const QObject*@receiver@,const char*@method@,Qt::ConnectionType@type@=Qt::AutoConnection)"
-                  return-type="QMetaObject::Connection">
+                  return-type="QMetaObject::Connection" overload-number="6">
         <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qobject-connect-6"/>
     </add-function>
 
        </modify-argument>
    </modify-function>
   </object-type>
-  <object-type name="QAbstractListModel" polymorphic-id-expression="qobject_cast&lt;QAbstractListModel*&gt;(%1)">
+  <object-type name="QAbstractListModel"
+               polymorphic-id-expression="qobject_cast&lt;QAbstractListModel*&gt;(%B)">
     <extra-includes>
       <include file-name="QStringList" location="global"/>
       <include file-name="QSize" location="global"/>
   </object-type>
   <value-type name="QUrlQuery"/>
 
-  <value-type name="QUrl" hash-function="PySide::hash">
+  <value-type name="QUrl">
     <!-- Qt5: lots of changes -->
     <enum-type name="ComponentFormattingOption" python-type="IntFlag" flags="ComponentFormattingOptions,FormattingOptions"/>
     <!-- note: above duplication of attribute is not by default XML compliant! -->
     <enum-type name="AceProcessingOption" flags="AceProcessingOptions" since="6.3"/>
     <extra-includes>
       <include file-name="QStringList" location="global"/>
-      <include file-name="pysideqhash.h" location="global"/>
     </extra-includes>
     <add-function signature="__repr__" return-type="PyObject*">
         <inject-code class="target" position="beginning">
   <value-type name="QOperatingSystemVersionBase" since="6.3">
       <enum-type name="OSType"/>
   </value-type>
+  <value-type name="QOperatingSystemVersionUnexported" since="6.3" generate="false"/>
   <value-type name="QOperatingSystemVersion">
-      <enum-type name="OSType"/>
       <modify-function signature="QOperatingSystemVersion(const QOperatingSystemVersionBase&amp;)" remove="all"/>
   </value-type>
   <object-type name="QLibrary">
           <inject-code file="../glue/qtcore.cpp" snippet="unlock"/>
       </add-function>
     </object-type>
+    <object-type name="QIOPipe"/>
     <value-type name="QGenericArgumentHolder"/>
     <value-type name="QGenericReturnArgumentHolder"/>
   </namespace-type>
         </modify-argument>
         <inject-code file="../glue/qtcore.cpp" snippet="qtranslator-load"/>
     </modify-function>
+    <modify-function signature="translate(const char*,const char*, const char*,int)const">
+        <modify-argument index="1" pyi-type="str"/>
+        <modify-argument index="2" pyi-type="str"/>
+        <modify-argument index="3" pyi-type="Optional[str]"/>
+    </modify-function>
   </object-type>
   <object-type name="QWaitCondition">
     <configuration condition="QT_CONFIG(thread)"/>
     <extra-includes>
       <include file-name="pysidestaticstrings.h" location="global"/>
     </extra-includes>
+    <inject-code class="native" position="beginning" file="../glue/qtcore.cpp"
+                 snippet="qtimer-singleshot-functorclass"/>
     <modify-function signature="singleShot(int,const QObject*,const char*)">
-      <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qtimer-singleshot-1"/>
+      <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qtimer-singleshot-direct-mapping"/>
     </modify-function>
-    <add-function signature="singleShot(int,PyCallable*)" static="yes">
-        <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qtimer-singleshot-2"/>
+    <add-function signature="singleShot(int@msec@,PyCallable*@functor@)" static="yes">
+        <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qtimer-singleshot-functor"/>
     </add-function>
     <add-function signature="singleShot(int@msec@,const QObject*@context@,PyCallable*@functor@)" static="yes">
         <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qtimer-singleshot-functor-context"/>
       <include file-name="pysidecleanup.h" location="global"/>
       <include file-name="pysideqapp.h" location="global"/>
     </extra-includes>
-    <!-- constructor documentation -->
-    <inject-documentation format="target" mode="append">
-.. class:: QCoreApplication(args)
-
-    Constructs a Qt kernel application. Kernel applications are applications
-    without a graphical user interface. These type of applications are used
-    at the console or as server processes.
-
-    The *args* argument is processed by the application, and made available
-    in a more convenient form by the :meth:`~QCoreApplication.arguments()`
-    method.
-    </inject-documentation>
-    <add-function signature="QCoreApplication(QStringList)">
+    <add-function signature="QCoreApplication(QStringList@args@)">
         <inject-code file="../glue/qtcore.cpp" snippet="qcoreapplication-1"/>
+        <inject-documentation format="target" mode="append">
+        Constructs a Qt kernel application. Kernel applications are applications
+        without a graphical user interface. These type of applications are used
+        at the console or as server processes.
+
+        The *args* argument is processed by the application, and made available
+        in a more convenient form by the :meth:`~PySide6.QtCore.QCoreApplication.arguments()`
+        method.
+        </inject-documentation>
     </add-function>
     <add-function signature="QCoreApplication()">
         <inject-code file="../glue/qtcore.cpp" snippet="qcoreapplication-2"/>
                      file="../glue/qtcore.cpp" snippet="repr-qevent"/>
     </add-function>
   </object-type>
-  <object-type name="QChildEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::ChildAdded || %1-&gt;type() == QEvent::ChildPolished || %1-&gt;type() == QEvent::ChildRemoved">
+  <object-type name="QChildEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::ChildAdded || %B-&gt;type() == QEvent::ChildPolished || %B-&gt;type() == QEvent::ChildRemoved">
     <modify-function signature="child()const">
       <modify-argument index="return">
          <define-ownership class="target" owner="default"/>
       </modify-argument>
     </modify-function>
   </object-type>
-  <object-type name="QTimerEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::Timer"/>
-  <object-type name="QDynamicPropertyChangeEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::DynamicPropertyChange"/>
+  <object-type name="QTimerEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::Timer"/>
+  <object-type name="QDynamicPropertyChangeEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::DynamicPropertyChange"/>
 
 
   <object-type name="QDataStream" stream="yes">
     <add-function signature="readQVariant()" return-type="QVariant">
         <inject-code class="target" position="end" file="../glue/qtcore.cpp" snippet="stream-read-method"/>
     </add-function>
-    <modify-function signature="readRawData(char*,int)">
+    <modify-function signature="readRawData(char*,qint64)">
         <modify-argument index="return" pyi-type="bytes"/>
         <modify-argument index="1">
             <remove-argument />
         <inject-code class="target" position="beginning"
                      file="../glue/qtcore.cpp" snippet="qdatastream-writerawdata-pybuffer"/>
     </add-function>
-    <modify-function signature="writeRawData(const char*,int)">
+    <modify-function signature="writeRawData(const char*,qint64)">
         <modify-argument index="1" pyi-type="str"/>
         <modify-argument index="2">
             <remove-argument />
     <add-function signature="writeString(QString)">
         <inject-code class="target" position="end" file="../glue/qtcore.cpp" snippet="stream-write-method"/>
     </add-function>
-    <modify-function signature="readBytes(char*&amp;,uint&amp;)">
+    <modify-function signature="readBytes(char*&amp;,qint64&amp;)">
         <modify-argument index="return">
             <replace-type modified-type="PyTuple"/>
         </modify-argument>
         </modify-argument>
         <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qdatastream-read-bytes"/>
     </modify-function>
+    <modify-function signature="readBytes(char*&amp;,uint&amp;)" remove="all"/>
 
-    <modify-function signature="writeBytes(const char*,uint)">
+    <modify-function signature="writeBytes(const char*,qint64)">
         <modify-argument index="1">
             <replace-type modified-type="PyBuffer"/>
             <conversion-rule class="native">
   </object-type>
   <value-type name="QModelIndex">
     <modify-function signature="internalPointer()const">
+        <modify-argument index="return" pyi-type="Any"/>
         <inject-code class="target" position="beginning">
             <insert-template name="return_internal_pointer" />
         </inject-code>
   <suppress-warning text="^signature 'readStringChunk\(char.*in 'QCborStreamReader' not found.*$"/>
 
   <!-- TODO: this need be removed -->
-  <suppress-warning text="^skipping function '.*', unmatched return type '.*$"/>
-  <suppress-warning text="^skipping function '.*', unmatched type '.*$"/>
-  <suppress-warning text="skipping field 'QStringConverter::iface' with unmatched type 'QStringConverter::Interface'"/>
-  <suppress-warning text="skipping field 'Qt::Uninitialized' with unmatched type 'Qt::Initialization'"/>
-  <suppress-warning text="skipping field 'State::clearFn' with unmatched type 'void'"/>
+  <suppress-warning text="^skipping.*function '.*', unmatched return type '.*$"/>
+  <suppress-warning text="^skipping.*function '.*', unmatched type '.*$"/>
+  <suppress-warning text="skipping protected field 'QStringConverter::iface' with unmatched type 'QStringConverter::Interface'"/>
+  <suppress-warning text="^skipping public field 'Qt::.*' with unmatched type 'Qt::.*ordering'$"/>
+  <suppress-warning text="skipping public field 'Qt::Uninitialized' with unmatched type 'Qt::Initialization'"/>
+  <suppress-warning text="skipping public field 'State::clearFn' with unmatched type 'void'"/>
   <suppress-warning text="template baseclass 'QListSpecialMethods&lt;T&gt;' of 'QList' is not known"/>
   <suppress-warning text="^.*inherits from a non polymorphic type.*QIODeviceBase.*type discovery based on RTTI is impossible.*$"/>
   <suppress-warning text="Base class 'QOperatingSystemVersionUnexported' of class 'QOperatingSystemVersion' not found in the type system for setting up inheritance."/>
index 02b26d7e562bcb5de216240733a5746246dca9e4..ebed2225773023ce8d7ab16f4f6621701eeec246 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2021 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtDBus">
+<typesystem package="PySide6.QtDBus"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
 
     <namespace-type name="QDBus">
     <value-type name="QDBusError">
       <enum-type name="ErrorType"/>
     </value-type>
-    <object-type name="QDBusInterface"/>
+    <object-type name="QDBusInterface" qt-metaobject="no">
+      <inject-documentation format="target" mode="append">
+        DBus signals can be captured with string-based connections
+        (see :ref:`signals-and-slots-strings`).
+      </inject-documentation>
+    </object-type>
     <value-type name="QDBusMessage">
       <enum-type name="MessageType"/>
     </value-type>
index b7ec9e4e2b496507b4393fdad0eb6bf597a151f5..1276b424f6fb6261dc043d356d2cb9ec64b46905 100644 (file)
@@ -54,10 +54,8 @@ set(QtDataVisualization_include_dirs ${QtDataVisualization_SOURCE_DIR}
                           ${QtCore_GEN_DIR}
                           ${QtGui_GEN_DIR})
 
-set(QtDataVisualization_libraries    pyside6
-                          ${Qt${QT_MAJOR_VERSION}DataVisualization_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES})
+set(QtDataVisualization_libraries pyside6
+                                  ${Qt${QT_MAJOR_VERSION}DataVisualization_LIBRARIES})
 
 set(QtDataVisualization_deps QtCore QtGui)
 
index 3df435c4510dfdb7a01c30db7d70965dc838c8c2..70014e3dc26de66535fa0a04683ca870422e1ea3 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2017 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtDataVisualization">
+<typesystem package="PySide6.QtDataVisualization"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
 
    <extra-includes>
       <include file-name="qtdatavisualization_helper.h" location="global"/>
index 20be3a7ded7e28dc2d3d8f713afd989bc881af18..e91532b87b228e7b26bf2c47c9208854638b3efc 100644 (file)
@@ -51,14 +51,11 @@ set(QtDesigner_include_dirs ${QtDesigner_SOURCE_DIR}
                             ${QtDesigner_BINARY_DIR}
                             ${QtCore_GEN_DIR}
                             ${QtGui_GEN_DIR}
-                            ${QtWidgets_GEN_DIR}
-                            )
+                            ${QtWidgets_GEN_DIR})
+
 set(QtDesigner_libraries pyside6
-                         ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                         ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                         ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
-                         ${Qt${QT_MAJOR_VERSION}Designer_LIBRARIES}
-                         )
+                         ${Qt${QT_MAJOR_VERSION}Designer_LIBRARIES})
+
 set(QtDesigner_deps QtWidgets)
 
 create_pyside_module(NAME QtDesigner
index 22b76e1319cdc07d62f4a9ef5f0ffd2050c8c56a..31f8ec15293b70f8d51e3cad4ec74e3c48686b59 100644 (file)
@@ -9,6 +9,8 @@
 #include <shiboken.h>
 #include <bindingmanager.h>
 
+QT_BEGIN_NAMESPACE
+
 static QString pyStringToQString(PyObject *s)
 {
     const char *utf8 = _PepUnicode_AsString(s);
@@ -217,3 +219,5 @@ void QPyDesignerCustomWidgetCollection::addCustomWidget(QDesignerCustomWidgetInt
 {
     instance()->m_customWidgets.append(c);
 }
+
+QT_END_NAMESPACE
index d82d681cc943f0849529db6c1a40599713af475e..7d37cbddf73493551ab10eabe478eba4b0dc20fe 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2021 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtDesigner">
+<typesystem package="PySide6.QtDesigner"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
 
   <rejection class="qdesigner_internal"/>
index 1fc47dc8ffa0df9d2358bb6d41a53fb29cf21a97..59cef220b1b9f09b857cb6406ce078fc634b2c3e 100644 (file)
@@ -3,9 +3,12 @@
 
 project(QtGraphs)
 
+set(QtGraphs_DROPPED_ENTRIES)
+
 list(APPEND QtGraphs_src "${QtGraphs_SOURCE_DIR}/qtgraphs_helper.cpp")
 
 set(QtGraphs_SRC
+# 3D
 ${QtGraphs_GEN_DIR}/qabstract3daxis_wrapper.cpp
 ${QtGraphs_GEN_DIR}/qcategory3daxis_wrapper.cpp
 ${QtGraphs_GEN_DIR}/qlogvalue3daxisformatter_wrapper.cpp
@@ -30,9 +33,6 @@ ${QtGraphs_GEN_DIR}/qsurface3dseries_wrapper.cpp
 ${QtGraphs_GEN_DIR}/qsurfacedataitem_wrapper.cpp
 ${QtGraphs_GEN_DIR}/qsurfacedataproxy_wrapper.cpp
 ${QtGraphs_GEN_DIR}/q3dbars_wrapper.cpp
-${QtGraphs_GEN_DIR}/q3dcamera_wrapper.cpp
-${QtGraphs_GEN_DIR}/q3dlight_wrapper.cpp
-${QtGraphs_GEN_DIR}/q3dobject_wrapper.cpp
 ${QtGraphs_GEN_DIR}/q3dscatter_wrapper.cpp
 ${QtGraphs_GEN_DIR}/q3dscene_wrapper.cpp
 ${QtGraphs_GEN_DIR}/q3dsurface_wrapper.cpp
@@ -41,6 +41,19 @@ ${QtGraphs_GEN_DIR}/q3dinputhandler_wrapper.cpp
 ${QtGraphs_GEN_DIR}/qabstract3dinputhandler_wrapper.cpp
 ${QtGraphs_GEN_DIR}/qtouch3dinputhandler_wrapper.cpp
 ${QtGraphs_GEN_DIR}/q3dtheme_wrapper.cpp
+# 2D
+${QtGraphs_GEN_DIR}/qbarcategoryaxis_wrapper.cpp
+${QtGraphs_GEN_DIR}/qabstractaxis_wrapper.cpp
+${QtGraphs_GEN_DIR}/qvalueaxis_wrapper.cpp
+${QtGraphs_GEN_DIR}/qabstractbarseries_wrapper.cpp
+${QtGraphs_GEN_DIR}/qbarseries_wrapper.cpp
+${QtGraphs_GEN_DIR}/qbarset_wrapper.cpp
+${QtGraphs_GEN_DIR}/qlineseries_wrapper.cpp
+${QtGraphs_GEN_DIR}/qabstractseries_wrapper.cpp
+${QtGraphs_GEN_DIR}/qscatterseries_wrapper.cpp
+${QtGraphs_GEN_DIR}/qgraphtheme_wrapper.cpp
+${QtGraphs_GEN_DIR}/qseriestheme_wrapper.cpp
+${QtGraphs_GEN_DIR}/qxyseries_wrapper.cpp
 # module is always needed
 ${QtGraphs_GEN_DIR}/qtgraphs_module_wrapper.cpp
 )
@@ -52,7 +65,6 @@ set(QtGraphs_include_dirs ${QtGraphs_SOURCE_DIR}
                           ${Qt${QT_MAJOR_VERSION}Gui_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Widgets_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Qml_INCLUDE_DIRS}
-                          ${Qt${QT_MAJOR_VERSION}OpenGL_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Quick_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}QuickWidgets_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Graphs_INCLUDE_DIRS}
@@ -63,24 +75,17 @@ set(QtGraphs_include_dirs ${QtGraphs_SOURCE_DIR}
                           ${QtGui_GEN_DIR}
                           ${QtWidgets_GEN_DIR}
                           ${QtQml_GEN_DIR}
-                          ${QtOpenGL_GEN_DIR}
                           ${QtQuick_GEN_DIR}
                           ${QtQuickWidgets_GEN_DIR}
                           ${QtQuick3D_GEN_DIR})
 
 set(QtGraphs_libraries    pyside6
-                          ${Qt${QT_MAJOR_VERSION}Graphs_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Qml_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}OpenGL_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Quick_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}QuickWidgets_LIBRARIES}
-                          ${Qt${QT_MAJOR_VERSION}Quick3D_LIBRARIES})
+                          ${Qt${QT_MAJOR_VERSION}Graphs_LIBRARIES})
+
+set(QtGraphs_deps QtCore QtNetwork QtGui QtWidgets QtQml QtQuick QtQuickWidgets QtQuick3D)
 
-set(QtGraphs_deps QtCore QtNetwork QtGui QtWidgets QtQml QtOpenGL QtQuick QtQuickWidgets QtQuick3D)
+check_qt_opengl("Graphs" QtGraphs_include_dirs QtGraphs_deps
+                QtGraphs_DROPPED_ENTRIES)
 
 create_pyside_module(NAME QtGraphs
                      INCLUDE_DIRS QtGraphs_include_dirs
@@ -88,7 +93,8 @@ create_pyside_module(NAME QtGraphs
                      DEPS QtGraphs_deps
                      TYPESYSTEM_PATH QtGraphs_SOURCE_DIR
                      SOURCES QtGraphs_SRC
-                     STATIC_SOURCES QtGraphs_src)
+                     STATIC_SOURCES QtGraphs_src
+                     DROPPED_ENTRIES QtGraphs_DROPPED_ENTRIES)
 
 install(FILES ${pyside6_SOURCE_DIR}/qtgraphs_helper.h
         DESTINATION include/PySide6/QtGraphs)
index 05d6b00a395870b981ef59ca664785aa798dce16..19fe4f818b4cd848fe31a83d81424327ecc13569 100644 (file)
@@ -18,28 +18,28 @@ static void populateArray(double xStart, double deltaX, double zStart, double de
     const qsizetype zStride = zStrideBytes / sizeof(T);
     double z = zStart;
     for (qsizetype zi = 0; zi < zSize; ++zi) {
-        auto *row = new QSurfaceDataRow;
-        row->reserve(xSize);
-        result->append(row);
+        QSurfaceDataRow row;
+        row.reserve(xSize);
 
         double x = xStart;
         auto *rowDataEnd = data + xSize;
         for (auto *d = data; d < rowDataEnd; ++d) {
-            row->append(QSurfaceDataItem(QVector3D(x, *d, z)));
+            row.append(QSurfaceDataItem(QVector3D(x, *d, z)));
             x += deltaX;
         }
+        result->append(row);
 
         data += zStride;
         z += deltaZ;
     }
 }
 
-QSurfaceDataArray *surfaceDataFromNp(double xStart, double deltaX, double zStart, double deltaZ,
-                                     PyObject *pyData)
+QSurfaceDataArray surfaceDataFromNp(double xStart, double deltaX, double zStart, double deltaZ,
+                                    PyObject *pyData)
 {
     static const char funcName[] = "QSurfaceDataProxy.resetArrayNp";
 
-    auto *result = new QSurfaceDataArray;
+    QSurfaceDataArray result;
 
     auto view = Shiboken::Numpy::View::fromPyObject(pyData);
     if (!view) {
@@ -59,35 +59,35 @@ QSurfaceDataArray *surfaceDataFromNp(double xStart, double deltaX, double zStart
     switch (view.type) {
     case Shiboken::Numpy::View::Int16:
         populateArray(xStart, deltaX, zStart, deltaZ, xSize, zSize, view.stride[0],
-                      reinterpret_cast<const int16_t *>(view.data), result);
+                      reinterpret_cast<const int16_t *>(view.data), &result);
         break;
     case Shiboken::Numpy::View::Unsigned16:
         populateArray(xStart, deltaX, zStart, deltaZ, xSize, zSize, view.stride[0],
-                      reinterpret_cast<const uint16_t *>(view.data), result);
+                      reinterpret_cast<const uint16_t *>(view.data), &result);
         break;
     case Shiboken::Numpy::View::Int:
         populateArray(xStart, deltaX, zStart, deltaZ, xSize, zSize, view.stride[0],
-                      reinterpret_cast<const int *>(view.data), result);
+                      reinterpret_cast<const int *>(view.data), &result);
         break;
     case Shiboken::Numpy::View::Unsigned:
         populateArray(xStart, deltaX, zStart, deltaZ, xSize, zSize, view.stride[0],
-                      reinterpret_cast<const unsigned *>(view.data), result);
+                      reinterpret_cast<const unsigned *>(view.data), &result);
         break;
     case Shiboken::Numpy::View::Int64:
         populateArray(xStart, deltaX, zStart, deltaZ, xSize, zSize, view.stride[0],
-                      reinterpret_cast<const int64_t *>(view.data), result);
+                      reinterpret_cast<const int64_t *>(view.data), &result);
         break;
     case Shiboken::Numpy::View::Unsigned64:
         populateArray(xStart, deltaX, zStart, deltaZ, xSize, zSize, view.stride[0],
-                      reinterpret_cast<const uint64_t *>(view.data), result);
+                      reinterpret_cast<const uint64_t *>(view.data), &result);
         break;
     case Shiboken::Numpy::View::Float:
         populateArray(xStart, deltaX, zStart, deltaZ, xSize, zSize, view.stride[0],
-                      reinterpret_cast<const float *>(view.data), result);
+                      reinterpret_cast<const float *>(view.data), &result);
         break;
     case Shiboken::Numpy::View::Double:
         populateArray(xStart, deltaX, zStart, deltaZ, xSize, zSize, view.stride[0],
-                      reinterpret_cast<const double *>(view.data), result);
+                      reinterpret_cast<const double *>(view.data), &result);
 
         break;
     }
index eb893b2a00818de6a730f38909250d790b8f8f38..43e4458be9f7e61fd293b2354d0adc95a2e89af8 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2023 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtGraphs">
+<typesystem package="PySide6.QtGraphs"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
 
    <extra-includes>
       <include file-name="qtgraphs_helper.h" location="global"/>
 
   <function signature="qDefaultSurfaceFormat(bool)"/>
 
-  <primitive-type name="QBarDataArray">
-    <include file-name="qbardataproxy.h" location="global"/>
-    <conversion-rule>
-        <native-to-target>
-            <insert-template name="cppqlistofptrtoqlists_to_py_conversion">
-              <replace from="%INTYPE_0" to="QBarDataItem"/>
-            </insert-template>
-        </native-to-target>
-        <target-to-native>
-            <add-conversion type="PySequence">
-                <insert-template name="py_to_cppqlistofptrtoqlists_conversion">
-                    <replace from="%OUTTYPE_0" to="QBarDataItem"/>
-                </insert-template>
-            </add-conversion>
-        </target-to-native>
-    </conversion-rule>
-  </primitive-type>
-  <primitive-type name="QSurfaceDataArray">
-    <include file-name="qsurfacedataproxy.h" location="global"/>
-    <conversion-rule>
-        <native-to-target>
-            <insert-template name="cppqlistofptrtoqlists_to_py_conversion">
-              <replace from="%INTYPE_0" to="QSurfaceDataItem"/>
-            </insert-template>
-        </native-to-target>
-        <target-to-native>
-            <add-conversion type="PySequence">
-                <insert-template name="py_to_cppqlistofptrtoqlists_conversion">
-                    <replace from="%OUTTYPE_0" to="QSurfaceDataItem"/>
-                </insert-template>
-            </add-conversion>
-        </target-to-native>
-    </conversion-rule>
-  </primitive-type>
 
   <object-type name="QAbstract3DAxis">
     <enum-type name="AxisOrientation"/>
   </modify-function>
   </object-type>
   <object-type name="QValue3DAxisFormatter">
-    <inject-code class="native" position="beginning" file="../glue/qtdatavisualization.cpp"
-                 snippet="qvalue3daxisformatter-friend"/>
     <modify-function signature="createNewInstance() const">
       <modify-argument index="return">
         <define-ownership class="native" owner="c++"/>
         <define-ownership class="target" owner="default"/>
       </modify-argument>
     </modify-function>
-    <!-- PYSIDE-2025: gridPositions(), labelPositions(), labelStrings() return
-         non-const-references to lists for modifications. Add setters for them. -->
-    <add-function signature="setGridPositions(const QList&lt;float&gt;&amp;@grid_positions@)">
-      <inject-documentation format="target" mode="append">
-      Sets the normalized grid line positions to ``grid_positions``.
-      </inject-documentation>
-      <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                   snippet="qvalue3daxisformatter-setgridpositions"/>
-    </add-function>
-    <add-function signature="setLabelPositions(const QList&lt;float&gt;&amp;@label_positions@)">
-      <inject-documentation format="target" mode="append">
-      Sets the normalized label positions to ``label_positions``.
-      </inject-documentation>
-      <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                   snippet="qvalue3daxisformatter-setlabelpositions"/>
-    </add-function>
-    <add-function signature="setLabelStrings(const QStringList&amp;@label_strings@)">
-      <inject-documentation format="target" mode="append">
-      Sets the label strings to ``label_strings``.
-      </inject-documentation>
-      <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                   snippet="qvalue3daxisformatter-setlabelstrings"/>
-    </add-function>
   </object-type>
   <object-type name="QAbstract3DSeries">
     <enum-type name="Mesh"/>
   </object-type>
   <value-type name="QBarDataItem"/>
   <object-type name="QBarDataProxy">
-    <modify-function signature="resetArray(QBarDataArray*)" remove="all"/>
-    <add-function signature="resetArray(const QBarDataArray&amp;)">
-      <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                   snippet="dataproxy-resetarray"/>
-    </add-function>
-    <modify-function signature="resetArray(QBarDataArray*,const QStringList&amp;,const QStringList&amp;)"
-                     remove="all"/>
-    <add-function signature="resetArray(const QBarDataArray&amp;,const QStringList&amp;,const QStringList&amp;)">
-      <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                   snippet="dataproxy-resetarray2"/>
-    </add-function>
-    <modify-function signature="resetArray(QBarDataArray*,const QStringList&amp;,const QStringList&amp;)">
-      <modify-argument index="1">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-
-    <!-- PYSIDE-1438: Replace all add/set/insertRow() taking a 'QList*' by overloads
-         taking 'const QList &' since an allocated list needs to be passed. -->
-    <modify-function signature="addRow(QList&lt;QBarDataItem&gt;*)" remove="all"/>
-    <add-function signature="addRow(const QList&lt;QBarDataItem&gt;&amp;)" return-type="int">
-        <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                     snippet="dataproxy-addrow"/>
-    </add-function>
-    <modify-function signature="addRow(QList&lt;QBarDataItem&gt;*,const QString&amp;)" remove="all"/>
-    <add-function signature="addRow(const QList&lt;QBarDataItem&gt;&amp;,const QString&amp;)"
-                  return-type="int">
-        <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                     snippet="dataproxy-addrow-string"/>
-    </add-function>
-
-    <modify-function signature="insertRow(int,QList&lt;QBarDataItem&gt;*)" remove="all"/>
-    <add-function signature="insertRow(int,const QList&lt;QBarDataItem&gt;&amp;)">
-        <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                     snippet="dataproxy-insertrow"/>
-    </add-function>
-    <modify-function signature="insertRow(int,QList&lt;QBarDataItem&gt;*,const QString&amp;)" remove="all"/>
-    <add-function signature="insertRow(int,const QList&lt;QBarDataItem&gt;&amp;, const QString&amp;)">
-        <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                     snippet="dataproxy-insertrow-string"/>
-    </add-function>
-
-    <modify-function signature="setRow(int,QList&lt;QBarDataItem&gt;*)" remove="all"/>
-    <add-function signature="setRow(int,const QList&lt;QBarDataItem&gt;&amp;)">
-        <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                     snippet="dataproxy-setrow"/>
-    </add-function>
-    <modify-function signature="setRow(int,QList&lt;QBarDataItem&gt;*,const QString&amp;)" remove="all"/>
-    <add-function signature="setRow(int,const QList&lt;QBarDataItem&gt;&amp;,const QString&amp;)">
-        <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                     snippet="dataproxy-setrow-string"/>
-    </add-function>
-
-    <modify-function signature="addRows(const QBarDataArray&amp;)">
-      <modify-argument index="1">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-    <modify-function signature="addRows(const QBarDataArray&amp;, const QStringList&amp;)">
-      <modify-argument index="1">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-    <modify-function signature="insertRows(int, const QBarDataArray&amp;)">
-      <modify-argument index="2">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-    <modify-function signature="insertRows(int, const QBarDataArray&amp;, const QStringList&amp;)">
-      <modify-argument index="2">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-    <modify-function signature="setRows(int, const QBarDataArray&amp;)">
-      <modify-argument index="2">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-    <modify-function signature="setRows(int, const QBarDataArray&amp;, const QStringList&amp;)">
-      <modify-argument index="2">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
   </object-type>
   <object-type name="QCustom3DItem"/>
   <object-type name="QCustom3DLabel"/>
   </object-type>
   <value-type name="QScatterDataItem"/>
   <object-type name="QScatterDataProxy">
-    <modify-function signature="resetArray(QList&lt;QScatterDataItem&gt;*)"
-                     remove="all"/>
-    <add-function signature="resetArray(QList&lt;QScatterDataItem&gt;*)">
-      <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                   snippet="scatterdataproxy-resetarray"/>
-    </add-function>
-    <modify-function signature="addItem(const QScatterDataItem&amp;)">
-      <modify-argument index="1">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-    <modify-function signature="addItems(const QList&lt;QScatterDataItem&gt;&amp;)">
-      <modify-argument index="1">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-    <modify-function signature="insertItem(int, const QScatterDataItem&amp;)">
-      <modify-argument index="2">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-    <modify-function signature="insertItems(int, const QList&lt;QScatterDataItem&gt;&amp;)">
-      <modify-argument index="2">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-    <modify-function signature="setItem(int, const QScatterDataItem&amp;)">
-      <modify-argument index="2">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
-    <modify-function signature="setItems(int, const QList&lt;QScatterDataItem&gt;&amp;)">
-      <modify-argument index="2">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </modify-function>
   </object-type>
   <object-type name="QSurface3DSeries">
     <enum-type name="DrawFlag" flags="DrawFlags"/>
       #include &lt;sbknumpycheck.h&gt;
       #include &lt;qtgraphs_helper.h&gt;
     </inject-code>
-    <!-- PYSIDE-1438: Replace all add/set/insertRow() taking a 'QList*' by overloads
-         taking 'const QList &' since an allocated list needs to be passed. -->
-    <modify-function signature="addRow(QList&lt;QSurfaceDataItem&gt;*)" remove="all"/>
-    <add-function signature="addRow(const QList&lt;QSurfaceDataItem&gt;&amp;)" return-type="int">
-        <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                     snippet="dataproxy-addrow"/>
-    </add-function>
-
-    <modify-function signature="insertRow(int,QList&lt;QSurfaceDataItem&gt;*)" remove="all"/>
-    <add-function signature="insertRow(int,const QList&lt;QSurfaceDataItem&gt;&amp;)">
-        <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                     snippet="dataproxy-insertrow"/>
-    </add-function>
-
-    <modify-function signature="setRow(int,QList&lt;QSurfaceDataItem&gt;*)" remove="all"/>
-    <add-function signature="setRow(int,const QList&lt;QSurfaceDataItem&gt;&amp;)">
-        <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                     snippet="dataproxy-setrow"/>
-    </add-function>
-
-    <modify-function signature="resetArray(QSurfaceDataArray*)" remove="all"/>
-    <add-function signature="resetArray(const QSurfaceDataArray&amp;)">
-      <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
-                   snippet="dataproxy-resetarray"/>
-      <modify-argument index="1">
-        <parent index="this" action="add"/>
-      </modify-argument>
-    </add-function>
-
     <add-function signature="resetArrayNp(double@x@,double@deltaX@,double@z@,double@deltaZ@,PyArrayObject*@data@)">
         <inject-code file="../glue/qtgraphs.cpp"
                      snippet="graphs-qsurfacedataproxy-resetarraynp"/>
       </modify-argument>
     </modify-function>
   </object-type>
-  <object-type name="Q3DCamera">
-    <enum-type name="CameraPreset"/>
-  </object-type>
-  <object-type name="Q3DLight"/>
-  <object-type name="Q3DObject"/>
   <object-type name="Q3DScatter">
     <modify-function signature="addAxis(QValue3DAxis*)">
       <modify-argument index="1">
     <enum-type name="RenderingMode"/>
     <enum-type name="SelectionFlag" flags="SelectionFlags"/>
     <enum-type name="ShadowQuality"/>
+    <enum-type name="CameraPreset" since="6.7"/>
     <modify-function signature="addCustomItem(QCustom3DItem*)">
       <modify-argument index="1">
         <parent index="this" action="add"/>
     <enum-type name="ColorStyle"/>
     <enum-type name="Theme"/>
   </object-type>
+
+  <!-- 2D -->
+  <object-type name="QBarCategoryAxis"/>
+  <object-type name="QAbstractAxis">
+    <enum-type name="AxisType"/>
+  </object-type>
+  <object-type name="QValueAxis"/>
+  <object-type name="QAbstractBarSeries">
+    <enum-type name="LabelsPosition"/>
+    <modify-function signature="append(QBarSet*)">
+      <modify-argument index="1">
+        <parent index="this" action="add"/>
+      </modify-argument>
+    </modify-function>
+    <modify-function signature="append(QList&lt;QBarSet*&gt;)">
+      <modify-argument index="1">
+        <parent index="this" action="add"/>
+      </modify-argument>
+    </modify-function>
+    <modify-function signature="insert(int,QBarSet*)">
+      <modify-argument index="2">
+        <parent index="this" action="add"/>
+      </modify-argument>
+    </modify-function>
+    <modify-function signature="take(QBarSet*)">
+      <modify-argument index="1">
+        <parent index="this" action="add"/>
+      </modify-argument>
+    </modify-function>
+  </object-type>
+  <object-type name="QBarSeries"/>
+  <object-type name="QBarSet"/>
+  <object-type name="QLineSeries"/>
+  <object-type name="QAbstractSeries">
+    <enum-type name="SeriesType"/>
+  </object-type>
+  <object-type name="QScatterSeries"/>
+  <object-type name="QGraphTheme">
+    <enum-type name="ColorTheme"/>
+  </object-type>
+  <object-type name="QSeriesTheme">
+    <enum-type name="SeriesColorTheme"/>
+  </object-type>
+  <object-type name="QXYSeries">
+  </object-type>
+
   <extra-includes>
     <include file-name="qutils.h" location="global"/>
   </extra-includes>
index da150af76f98b21349bf190616cd904bb50e37a3..99e0789d1326364975de25e6dac7c9d1404d29c7 100644 (file)
@@ -25,10 +25,9 @@ ${QtGui_GEN_DIR}/qrhicommandbuffer_wrapper.cpp
 ${QtGui_GEN_DIR}/qrhicomputepipeline_wrapper.cpp
 ${QtGui_GEN_DIR}/qrhidepthstencilclearvalue_wrapper.cpp
 ${QtGui_GEN_DIR}/qrhidriverinfo_wrapper.cpp
-${QtGui_GEN_DIR}/qrhigles2initparams_wrapper.cpp
-${QtGui_GEN_DIR}/qrhigles2nativehandles_wrapper.cpp
 ${QtGui_GEN_DIR}/qrhigraphicspipeline_targetblend_wrapper.cpp
 ${QtGui_GEN_DIR}/qrhigraphicspipeline_wrapper.cpp
+${QtGui_GEN_DIR}/qrhigraphicspipeline_stencilopstate_wrapper.cpp
 ${QtGui_GEN_DIR}/qrhiinitparams_wrapper.cpp
 ${QtGui_GEN_DIR}/qrhinativehandles_wrapper.cpp
 ${QtGui_GEN_DIR}/qrhinullinitparams_wrapper.cpp
@@ -89,6 +88,7 @@ ${QtGui_GEN_DIR}/qaccessibleactioninterface_wrapper.cpp
 ${QtGui_GEN_DIR}/qaccessibleeditabletextinterface_wrapper.cpp
 ${QtGui_GEN_DIR}/qaccessibleevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qaccessibleobject_wrapper.cpp
+${QtGui_GEN_DIR}/qaccessibleselectioninterface_wrapper.cpp
 ${QtGui_GEN_DIR}/qaccessiblestatechangeevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qaccessibletablecellinterface_wrapper.cpp
 ${QtGui_GEN_DIR}/qaccessibletablemodelchangeevent_wrapper.cpp
@@ -106,6 +106,7 @@ ${QtGui_GEN_DIR}/qactiongroup_wrapper.cpp
 ${QtGui_GEN_DIR}/qbackingstore_wrapper.cpp
 ${QtGui_GEN_DIR}/qbitmap_wrapper.cpp
 ${QtGui_GEN_DIR}/qbrush_wrapper.cpp
+${QtGui_GEN_DIR}/qchildwindowevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qclipboard_wrapper.cpp
 ${QtGui_GEN_DIR}/qcloseevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qcolor_wrapper.cpp
@@ -129,6 +130,7 @@ ${QtGui_GEN_DIR}/qexposeevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qfileopenevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qfocusevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qfont_wrapper.cpp
+${QtGui_GEN_DIR}/qfont_tag_wrapper.cpp
 ${QtGui_GEN_DIR}/qfontdatabase_wrapper.cpp
 ${QtGui_GEN_DIR}/qfontinfo_wrapper.cpp
 ${QtGui_GEN_DIR}/qfontmetrics_wrapper.cpp
@@ -170,10 +172,8 @@ ${QtGui_GEN_DIR}/qmouseevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qmoveevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qmovie_wrapper.cpp
 ${QtGui_GEN_DIR}/qnativegestureevent_wrapper.cpp
+${QtGui_GEN_DIR}/qnativeinterface_wrapper.cpp
 ${QtGui_GEN_DIR}/qoffscreensurface_wrapper.cpp
-${QtGui_GEN_DIR}/qopenglcontextgroup_wrapper.cpp
-${QtGui_GEN_DIR}/qopenglextrafunctions_wrapper.cpp
-${QtGui_GEN_DIR}/qopenglfunctions_wrapper.cpp
 ${QtGui_GEN_DIR}/qpagedpaintdevice_wrapper.cpp
 ${QtGui_GEN_DIR}/qpagelayout_wrapper.cpp
 ${QtGui_GEN_DIR}/qpageranges_wrapper.cpp
@@ -217,7 +217,6 @@ ${QtGui_GEN_DIR}/qsinglepointevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qstandarditem_wrapper.cpp
 ${QtGui_GEN_DIR}/qstandarditemmodel_wrapper.cpp
 ${QtGui_GEN_DIR}/qstatustipevent_wrapper.cpp
-${QtGui_GEN_DIR}/qopenglcontext_wrapper.cpp
 ${QtGui_GEN_DIR}/qaccessible_state_wrapper.cpp
 ${QtGui_GEN_DIR}/qaccessibleinterface_wrapper.cpp
 ${QtGui_GEN_DIR}/qscreen_wrapper.cpp
@@ -283,6 +282,33 @@ ${QtGui_GEN_DIR}/qwindowstatechangeevent_wrapper.cpp
 ${QtGui_GEN_DIR}/qtgui_module_wrapper.cpp
 )
 
+get_property(QtGui_enabled_features TARGET Qt${QT_MAJOR_VERSION}::Gui
+             PROPERTY QT_ENABLED_PUBLIC_FEATURES)
+
+if("xcb" IN_LIST QtGui_enabled_features)
+    list(APPEND QtGui_SRC
+         ${QtGui_GEN_DIR}/qnativeinterface_qx11application_wrapper.cpp)
+elseif(WIN32)
+    list(APPEND QtGui_SRC
+         ${QtGui_GEN_DIR}/qnativeinterface_qwindowsscreen_wrapper.cpp)
+endif()
+
+if("opengl" IN_LIST QtGui_enabled_features OR "opengles2" IN_LIST QtGui_enabled_features
+   OR "opengles3" IN_LIST QtGui_enabled_features)
+    list(APPEND QtGui_SRC
+         ${QtGui_GEN_DIR}/qopenglcontextgroup_wrapper.cpp
+         ${QtGui_GEN_DIR}/qopenglextrafunctions_wrapper.cpp
+         ${QtGui_GEN_DIR}/qopenglfunctions_wrapper.cpp
+         ${QtGui_GEN_DIR}/qopenglcontext_wrapper.cpp
+         ${QtGui_GEN_DIR}/qrhigles2initparams_wrapper.cpp
+         ${QtGui_GEN_DIR}/qrhigles2nativehandles_wrapper.cpp)
+else()
+    list(APPEND QtGui_DROPPED_ENTRIES
+         QOpenGLContext QOpenGLContextGroup QOpenGLPaintDevice
+         QOpenGLExtraFunctions QOpenGLFunctions
+         QRhiGles2InitParams QRhiGles2NativeHandles)
+endif()
+
 set(QtGui_private_include_dirs
     ${Qt${QT_MAJOR_VERSION}Core_PRIVATE_INCLUDE_DIRS}
     ${Qt${QT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS})
index 29c221f3aedb8f1b80d9f6a2ee46ff326576a9b4..858989404660c4b038a768284cf4ce3791f34034 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtGui">
+<typesystem package="PySide6.QtGui"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <?if windows?>
     <load-typesystem name="QtGui/typesystem_gui_win.xml" generate="yes"/>
index 7aaa6fe2cf561a86799afe42a9829a8262d38c9f..0cab80a149acd490494b5571ea5e13d817e82894 100644 (file)
   <object-type name="QAccessibleEditableTextInterface"/>
   <object-type name="QAccessibleInterface"/>
   <object-type name="QAccessibleObject" qt-register-metatype="base"/>
+  <object-type name="QAccessibleSelectionInterface" since="6.7"/>
   <object-type name="QAccessibleTableCellInterface"/>
   <object-type name="QAccessibleTextInterface"/>
   <object-type name="QAccessibleValueInterface"/>
 
-  <object-type name="QAccessibleEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QAccessible::InvalidEvent"/>
-  <object-type name="QAccessibleStateChangeEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QAccessible::StateChanged"/>
-  <object-type name="QAccessibleTableModelChangeEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QAccessible::TableModelChanged">
+  <object-type name="QAccessibleEvent"
+               polymorphic-id-expression="%B-&gt;type() == QAccessible::InvalidEvent"/>
+  <object-type name="QAccessibleStateChangeEvent"
+               polymorphic-id-expression="%B-&gt;type() == QAccessible::StateChanged"/>
+  <object-type name="QAccessibleTableModelChangeEvent"
+                    polymorphic-id-expression="%B-&gt;type() == QAccessible::TableModelChanged">
       <enum-type name="ModelChangeType"/>
   </object-type>
-  <object-type name="QAccessibleTextCursorEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QAccessible::TextCaretMoved"/>
-  <object-type name="QAccessibleTextInsertEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QAccessible::TextInserted"/>
-  <object-type name="QAccessibleTextRemoveEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QAccessible::TextRemoved"/>
-  <object-type name="QAccessibleTextSelectionEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QAccessible::TextSelectionChanged"/>
-  <object-type name="QAccessibleTextUpdateEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QAccessible::TextUpdated"/>
-  <object-type name="QAccessibleValueChangeEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QAccessible::ValueChanged"/>
+  <object-type name="QAccessibleTextCursorEvent"
+               polymorphic-id-expression="%B-&gt;type() == QAccessible::TextCaretMoved"/>
+  <object-type name="QAccessibleTextInsertEvent"
+               polymorphic-id-expression="%B-&gt;type() == QAccessible::TextInserted"/>
+  <object-type name="QAccessibleTextRemoveEvent"
+               polymorphic-id-expression="%B-&gt;type() == QAccessible::TextRemoved"/>
+  <object-type name="QAccessibleTextSelectionEvent"
+               polymorphic-id-expression="%B-&gt;type() == QAccessible::TextSelectionChanged"/>
+  <object-type name="QAccessibleTextUpdateEvent"
+               polymorphic-id-expression="%B-&gt;type() == QAccessible::TextUpdated"/>
+  <object-type name="QAccessibleValueChangeEvent"
+               polymorphic-id-expression="%B-&gt;type() == QAccessible::ValueChanged"/>
 
   <object-type name="QAction">
     <enum-type name="ActionEvent"/>
   <value-type name="QIcon" >
     <enum-type name="Mode"/>
     <enum-type name="State"/>
+    <enum-type name="ThemeIcon" since="6.7"/>
     <modify-function signature="QIcon(QIconEngine*)">
       <modify-argument index="1">
         <no-null-pointer/>
     </modify-function>
   </value-type>
 
-  <value-type name="QConicalGradient" polymorphic-id-expression="%1-&gt;type() == QGradient::ConicalGradient"/>
+  <value-type name="QConicalGradient" polymorphic-id-expression="%B-&gt;type() == QGradient::ConicalGradient"/>
   <value-type name="QFontInfo"/>
-  <value-type name="QRadialGradient" polymorphic-id-expression="%1-&gt;type() == QGradient::RadialGradient"/>
+  <value-type name="QRadialGradient" polymorphic-id-expression="%B-&gt;type() == QGradient::RadialGradient"/>
   <value-type name="QFont" >
     <enum-type name="Capitalization"/>
     <enum-type name="SpacingType"/>
     <extra-includes>
       <include file-name="QStringList" location="global"/>
     </extra-includes>
+    <value-type name="Tag" since="6.7"/>
     <!-- PYSIDE-1685: QFont(QString) should be checked first, else it will be interpreted as sequence -->
     <modify-function signature="QFont(const QString&amp;,int,int, bool)" overload-number="0"/>
     <modify-function signature="QFont(const QStringList &amp;,int,int, bool)" overload-number="1"/>
       <inject-code class="target" position="beginning" file="../glue/qtgui.cpp" snippet="qfontmetrics-size"/>
     </modify-function>
   </value-type>
-  <value-type name="QGradient" polymorphic-id-expression="%1-&gt;type() == QGradient::NoGradient">
+  <value-type name="QGradient" polymorphic-id-expression="%B-&gt;type() == QGradient::NoGradient">
       <enum-type name="CoordinateMode"/>
       <enum-type name="InterpolationMode"/>
       <enum-type name="Preset"/>
       <enum-type name="Spread"/>
       <enum-type name="Type"/>
   </value-type>
-  <value-type name="QLinearGradient" polymorphic-id-expression="%1-&gt;type() == QGradient::LinearGradient"/>
+  <value-type name="QLinearGradient" polymorphic-id-expression="%B-&gt;type() == QGradient::LinearGradient"/>
   <object-type name="QPaintDevice">
       <enum-type name="PaintDeviceMetric"/>
   </object-type>
     </modify-function>
   </object-type>
 
-  <object-type name="QActionEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::ActionAdded || %1-&gt;type() == QEvent::ActionRemoved || %1-&gt;type() == QEvent::ActionChanged"/>
-  <object-type name="QCloseEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::Close"/>
-  <object-type name="QContextMenuEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::ContextMenu">
+  <object-type name="QActionEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::ActionAdded || %B-&gt;type() == QEvent::ActionRemoved || %B-&gt;type() == QEvent::ActionChanged"/>
+  <object-type name="QCloseEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::Close"/>
+  <object-type name="QContextMenuEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::ContextMenu">
       <enum-type name="Reason"/>
   </object-type>
 
   <value-type name="QEventPoint">
       <enum-type name="State"/>
   </value-type>
-  <object-type name="QDragEnterEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::DragEnter">
+  <object-type name="QDragEnterEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::DragEnter">
       <add-function signature="__repr__" return-type="PyObject">
           <inject-code class="target" position="beginning">
               <insert-template name="repr_qdebug_gui"/>
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QDragLeaveEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::DragLeave">
+  <object-type name="QDragLeaveEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::DragLeave">
       <add-function signature="__repr__" return-type="PyObject">
           <inject-code class="target" position="beginning">
               <insert-template name="repr_qdebug_gui"/>
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QDragMoveEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::DragMove">
+  <object-type name="QDragMoveEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::DragMove">
       <add-function signature="__repr__" return-type="PyObject">
           <inject-code class="target" position="beginning">
               <insert-template name="repr_qdebug_gui"/>
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QDropEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::Drop">
+  <object-type name="QDropEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::Drop">
     <modify-function signature="source()const">
       <modify-argument index="return">
         <define-ownership class="target" owner="default"/>
         </inject-code>
     </add-function>
   </object-type>
-  <object-type name="QEnterEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::Enter"/>
-  <object-type name="QExposeEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::Expose"/>
-  <object-type name="QFileOpenEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::FileOpen"/>
-  <object-type name="QFocusEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::FocusIn || %1-&gt;type() == QEvent::FocusOut">
+  <object-type name="QChildWindowEvent" since="6.7"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::ChildWindowAdded || %B-&gt;type() == QEvent::ChildWindowRemoved"/>
+  <object-type name="QEnterEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::Enter"/>
+  <object-type name="QExposeEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::Expose"/>
+  <object-type name="QFileOpenEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::FileOpen"/>
+  <object-type name="QFocusEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::FocusIn || %B-&gt;type() == QEvent::FocusOut">
       <add-function signature="__repr__" return-type="PyObject">
           <inject-code class="target" position="beginning">
               <insert-template name="repr_qdebug_gui"/>
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QHelpEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::ToolTip || %1-&gt;type() == QEvent::WhatsThis"/>
-  <object-type name="QHideEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::Hide"/>
-  <object-type name="QHoverEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::HoverEnter || %1-&gt;type() == QEvent::HoverLeave || %1-&gt;type() == QEvent::HoverMove"/>
-  <object-type name="QIconDragEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::IconDrag"/>
+  <object-type name="QHelpEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::ToolTip || %B-&gt;type() == QEvent::WhatsThis"/>
+  <object-type name="QHideEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::Hide"/>
+  <object-type name="QHoverEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::HoverEnter || %B-&gt;type() == QEvent::HoverLeave || %B-&gt;type() == QEvent::HoverMove"/>
+  <object-type name="QIconDragEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::IconDrag"/>
 
-  <object-type name="QInputMethodEvent" copyable="no" polymorphic-id-expression="%1-&gt;type() == QEvent::InputMethod">
+  <object-type name="QInputMethodEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::InputMethod">
     <!-- only declare this if ndef QT_NO_INPUTMETHOD -->
     <enum-type name="AttributeType"/>
     <value-type name="Attribute">
     </add-function>
     <!-- endif ndef QT_NO_INPUTMETHOD -->
   </object-type>
-  <object-type name="QInputMethodQueryEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::InputMethodQuery"/>
+  <object-type name="QInputMethodQueryEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::InputMethodQuery"/>
 
-  <object-type name="QMoveEvent" copyable = "false" polymorphic-id-expression="%1-&gt;type() == QEvent::Move">
+  <object-type name="QMoveEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::Move">
       <add-function signature="__repr__" return-type="PyObject">
           <inject-code class="target" position="beginning">
               <insert-template name="repr_qdebug_gui"/>
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QNativeGestureEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::NativeGesture"/>
-  <object-type name="QPlatformSurfaceEvent" copyable="false"
-               polymorphic-id-expression="%1-&gt;type() == QEvent::PlatformSurface">
+  <object-type name="QNativeGestureEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::NativeGesture"/>
+  <object-type name="QPlatformSurfaceEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::PlatformSurface">
      <enum-type name="SurfaceEventType"/>
   </object-type>
-  <object-type name="QResizeEvent" copyable = "false" polymorphic-id-expression="%1-&gt;type() == QEvent::Resize">
+  <object-type name="QResizeEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::Resize">
       <add-function signature="__repr__" return-type="PyObject">
           <inject-code class="target" position="beginning">
               <insert-template name="repr_qdebug_gui"/>
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QShortcutEvent" copyable = "false" polymorphic-id-expression="%1-&gt;type() == QEvent::Shortcut">
+  <object-type name="QShortcutEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::Shortcut">
   </object-type>
-  <object-type name="QShowEvent" copyable= "false" polymorphic-id-expression="%1-&gt;type() == QEvent::Show"/>
-  <object-type name="QSinglePointEvent" copyable="false"/>
-  <object-type name="QStatusTipEvent" copyable= "false" polymorphic-id-expression="%1-&gt;type() == QEvent::StatusTip"/>
-  <object-type name="QTabletEvent" copyable= "false" polymorphic-id-expression="%1-&gt;type() == QEvent::TabletMove || %1-&gt;type() == QEvent::TabletPress || %1-&gt;type() == QEvent::TabletRelease">
+  <object-type name="QShowEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::Show"/>
+  <object-type name="QSinglePointEvent"/>
+  <object-type name="QStatusTipEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::StatusTip"/>
+  <object-type name="QTabletEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::TabletMove || %B-&gt;type() == QEvent::TabletPress || %B-&gt;type() == QEvent::TabletRelease">
       <add-function signature="__repr__" return-type="PyObject">
           <inject-code class="target" position="beginning">
               <insert-template name="repr_qdebug_gui"/>
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QToolBarChangeEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::ToolBarChange"/>
-  <object-type name="QWhatsThisClickedEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::WhatsThisClicked"/>
-  <object-type name="QWheelEvent" copyable= "false" polymorphic-id-expression="%1-&gt;type() == QEvent::Wheel">
+  <object-type name="QToolBarChangeEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::ToolBarChange"/>
+  <object-type name="QWhatsThisClickedEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::WhatsThisClicked"/>
+  <object-type name="QWheelEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::Wheel">
       <add-function signature="__repr__" return-type="PyObject">
           <inject-code class="target" position="beginning">
               <insert-template name="repr_qdebug_gui"/>
       </add-function>
   </object-type>
 
-  <object-type name="QWindowStateChangeEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::WindowStateChange">
+  <object-type name="QWindowStateChangeEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::WindowStateChange">
       <add-function signature="__repr__" return-type="PyObject">
           <inject-code class="target" position="beginning">
               <insert-template name="repr_qdebug_gui"/>
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QInputEvent" copyable="false"/>
-  <object-type name="QKeyEvent" copyable= "false" polymorphic-id-expression="%1-&gt;type() == QEvent::KeyPress || %1-&gt;type() == QEvent::KeyRelease || %1-&gt;type() == QEvent::ShortcutOverride">
+  <object-type name="QInputEvent"/>
+  <object-type name="QKeyEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::KeyPress || %B-&gt;type() == QEvent::KeyRelease || %B-&gt;type() == QEvent::ShortcutOverride">
       <add-function signature="operator!=(QKeySequence::StandardKey)">
           <inject-code class="target" file="../glue/qtgui.cpp" snippet="qkeyevent-operatornotequal"/>
       </add-function>
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QMouseEvent" copyable= "false"
-               polymorphic-id-expression="%1-&gt;type() == QEvent::MouseButtonDblClick || %1-&gt;type() == QEvent::MouseButtonPress || %1-&gt;type() == QEvent::MouseButtonRelease || %1-&gt;type() == QEvent::MouseMove">
+  <object-type name="QMouseEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::MouseButtonDblClick || %B-&gt;type() == QEvent::MouseButtonPress || %B-&gt;type() == QEvent::MouseButtonRelease || %B-&gt;type() == QEvent::MouseMove">
       <modify-function signature="globalPos() const" deprecated="yes"/>
       <modify-function signature="localPos() const" deprecated="yes"/>
       <modify-function signature="pos() const" deprecated="yes"/>
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QPaintEvent" copyable= "false" polymorphic-id-expression="%1-&gt;type() == QEvent::Paint"/>
-  <object-type name="QScrollEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::Scroll">
+  <object-type name="QPaintEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::Paint"/>
+  <object-type name="QScrollEvent" polymorphic-id-expression="%B-&gt;type() == QEvent::Scroll">
       <enum-type name="ScrollState"/>
   </object-type>
   <object-type name="QPointerEvent" copyable= "false">
           </inject-code>
       </add-function>
   </object-type>
-  <object-type name="QScrollPrepareEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::ScrollPrepare"/>
+  <object-type name="QScrollPrepareEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::ScrollPrepare"/>
 
   <object-type name="QTextFrame" >
     <extra-includes>
     </add-function>
   </object-type>
 
-  <object-type name="QStandardItemModel" polymorphic-id-expression="qobject_cast&lt;QStandardItemModel*&gt;(%1)">
+  <object-type name="QStandardItemModel" polymorphic-id-expression="qobject_cast&lt;QStandardItemModel*&gt;(%B)">
     <extra-includes>
       <include file-name="QStringList" location="global"/>
       <include file-name="QSize" location="global"/>
         </inject-code>
     </add-function>
 
-    <!-- Qt5.5: XXX support the output variables! For now, I just suppressed the new methods. -->
-    <modify-function signature="getAxisAndAngle(float*,float*,float*,float*)const"/>
-    <modify-function signature="getAxisAndAngle(QVector3D*,float*)const"/>
-    <modify-function signature="getEulerAngles(float*,float*,float*)const"/>
+    <!-- There can be only one return type.  -->
+    <modify-function signature="getAxisAndAngle(float*,float*,float*,float*)const" remove="all"/>
+    <modify-function signature="getAxisAndAngle(QVector3D*,float*)const">
+        <modify-argument index="return" pyi-type="Tuple[PySide6.QtGui.QVector3D, float]">
+            <replace-type modified-type="(QVector3D, float)"/>
+        </modify-argument>
+        <modify-argument index="1"><remove-argument/></modify-argument>
+        <modify-argument index="2"><remove-argument/></modify-argument>
+        <inject-code class="target" position="beginning"
+                     file="../glue/qtgui.cpp" snippet="qquaternion-getaxisandangle-vector3d-float"/>
+    </modify-function>
+    <modify-function signature="getEulerAngles(float*,float*,float*)const">
+        <modify-argument index="return" pyi-type="Tuple[float, float, float]">
+            <replace-type modified-type="(float, float, float)"/>
+        </modify-argument>
+        <modify-argument index="1"><remove-argument/></modify-argument>
+        <modify-argument index="2"><remove-argument/></modify-argument>
+        <modify-argument index="3"><remove-argument/></modify-argument>
+        <inject-code class="target" position="beginning"
+                     file="../glue/qtgui.cpp" snippet="qquaternion-geteulerangles"/>
+    </modify-function>
   </value-type>
 
   <object-type name="QTouchEvent" since="4.6">
     <add-function signature="exec_()" return-type="int">
         <inject-code file="../glue/qtgui.cpp" snippet="qguiapplication-exec"/>
     </add-function>
+    <add-function signature="nativeInterface()const" return-type="PyObject">
+        <modify-argument index="return"> <!-- Suppress return value heuristics -->
+            <define-ownership class="target" owner="default"/>
+        </modify-argument>
+        <inject-code class="target" position="beginning" file="../glue/qtgui.cpp"
+                     snippet="qguiapplication-nativeInterface"/>
+    </add-function>
     <modify-function signature="setOverrideCursor(const QCursor&amp;)">
         <modify-argument index="return" pyi-type="PyObject">
             <replace-type modified-type="QtGuiHelper::QOverrideCursorGuard*"/>
     </modify-function>
   </object-type>
 
+  <namespace-type name="QNativeInterface" private="yes" since="6.7">
+      <object-type name="QX11Application" private="yes" disable-wrapper="yes"
+                   force-abstract="yes">
+          <configuration condition="QT_CONFIG(xcb)"/>
+          <modify-function signature="display()const">
+              <modify-argument index="return">
+                  <replace-type modified-type="int"/>
+              </modify-argument>
+              <inject-code class="target" position="end" file="../glue/qtgui.cpp"
+                           snippet="qx11application-resource-ptr"/>
+          </modify-function>
+          <modify-function signature="connection()const">
+              <modify-argument index="return">
+                  <replace-type modified-type="int"/>
+              </modify-argument>
+              <inject-code class="target" position="end" file="../glue/qtgui.cpp"
+                           snippet="qx11application-resource-ptr"/>
+          </modify-function>
+      </object-type>
+      <object-type name="QWindowsScreen" private="yes" disable-wrapper="yes"
+                   force-abstract="yes">
+          <configuration condition="#ifdef Q_OS_WIN"/>
+      </object-type>
+  </namespace-type>
+
   <object-type name="QOpenGLContext">
     <enum-type name="OpenGLModuleType"/>
   </object-type>
         </modify-argument>
         <inject-code file="../glue/qtgui.cpp" snippet="qscreen-grabWindow"/>
       </modify-function>
+      <add-function signature="nativeInterface()const" return-type="PyObject">
+          <modify-argument index="return"> <!-- Suppress return value heuristics -->
+              <define-ownership class="target" owner="default"/>
+          </modify-argument>
+          <inject-code class="target" position="beginning" file="../glue/qtgui.cpp"
+                       snippet="qscreen-nativeInterface"/>
+      </add-function>
   </object-type>
   <object-type name="QStyleHints"/>
 
index d3727675179a135c2fdb599d4dcf9b7afa8f757f..22ab56e20f51c0fd6027b0fb21ee0064bcf9ddcb 100644 (file)
       <enum-type name="CompareOp"/>
       <enum-type name="StencilOp"/>
       <enum-type name="PolygonMode"/>
+      <value-type name="StencilOpState" private="yes"/>
       <value-type name="TargetBlend" private="yes"/>
       <add-function signature="setShaderStages(QList&lt;QRhiShaderStage&gt;@stages@)">
           <inject-code class="target" position="beginning"
index 89e3a33fe7482895c5c29849a712d23f251a18b0..b3b8a75b698af7d5385b9aab4d769114436ef27e 100644 (file)
             </target-to-native>
         </conversion-rule>
     </primitive-type>
+    <primitive-type name="HMONITOR" target-lang-api-name="PyLong">
+        <conversion-rule>
+            <native-to-target file="../glue/qtgui.cpp" snippet="return-pylong-voidptr"/>
+            <target-to-native>
+                <add-conversion type="PyLong" file="../glue/qtgui.cpp"
+                                snippet="conversion-pylong"/>
+            </target-to-native>
+        </conversion-rule>
+    </primitive-type>
     <primitive-type name="HRGN" target-lang-api-name="PyLong">
         <conversion-rule>
             <native-to-target file="../glue/qtgui.cpp" snippet="return-pylong-voidptr"/>
index c4f16911e3e0bb0a310fd3c604aeaca7d76df785..70331e29c8878341548ee2ca5f817dbda9b31893 100644 (file)
@@ -3,4 +3,7 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtGui"/>
+<typesystem package="PySide6.QtGui">
+    <custom-type name="_XDisplay"/>
+    <custom-type name="xcb_connection_t"/>
+</typesystem>
index 88697dbab5536a26d0fc28f6685cf78b96b3856b..7bf46dcefaaeb2bc437f25748c799d69e577443b 100644 (file)
@@ -8,6 +8,7 @@ ${QtHelp_GEN_DIR}/qcompressedhelpinfo_wrapper.cpp
 ${QtHelp_GEN_DIR}/qhelpcontentitem_wrapper.cpp
 ${QtHelp_GEN_DIR}/qhelpcontentmodel_wrapper.cpp
 ${QtHelp_GEN_DIR}/qhelpcontentwidget_wrapper.cpp
+${QtHelp_GEN_DIR}/qhelpglobal_wrapper.cpp
 ${QtHelp_GEN_DIR}/qhelpengine_wrapper.cpp
 ${QtHelp_GEN_DIR}/qhelpenginecore_wrapper.cpp
 ${QtHelp_GEN_DIR}/qhelpfilterdata_wrapper.cpp
@@ -40,9 +41,6 @@ set(QtHelp_include_dirs ${QtHelp_SOURCE_DIR}
                         ${QtCore_GEN_DIR}
                         )
 set(QtHelp_libraries  pyside6
-                      ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
                       ${Qt${QT_MAJOR_VERSION}Help_LIBRARIES})
 
 set(QtHelp_deps QtWidgets)
index 88712bfb702cf2de78179f0b9db852a73846beed..5fa30e03473b33e53e036acc1697fb3c7b7c8cb9 100644 (file)
@@ -4,7 +4,8 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.QtHelp">
+<typesystem package="PySide6.QtHelp"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
 
     <value-type name="QCompressedHelpInfo"/>
@@ -15,8 +16,9 @@
         </modify-argument>
       </modify-function>
     </value-type>
-    <object-type name="QHelpContentModel" polymorphic-id-expression="qobject_cast&lt;QHelpContentModel*&gt;(%1)"/>
+    <object-type name="QHelpContentModel" polymorphic-id-expression="qobject_cast&lt;QHelpContentModel*&gt;(%B)"/>
     <object-type name="QHelpContentWidget"/>
+    <value-type name="QHelpGlobal"/>
     <object-type name="QHelpEngine"/>
     <object-type name="QHelpEngineCore"/>
     <value-type name="QHelpFilterData"/>
index 9bd43e62bd7a93686d7ec2844fe3fad7db0f2985..c931f064f62681149b4cd4341aae63cfef058502 100644 (file)
@@ -28,11 +28,7 @@ set(QtHttpServer_include_dirs ${QtHttpServer_SOURCE_DIR}
                                 ${QtWebSockets_GEN_DIR})
 
 set(QtHttpServer_libraries pyside6
-                           ${Qt${QT_MAJOR_VERSION}HttpServer_LIBRARIES}
-                           ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                           ${Qt${QT_MAJOR_VERSION}Concurrent_LIBRARIES}
-                           ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                           ${Qt${QT_MAJOR_VERSION}WebSockets_LIBRARIES})
+                           ${Qt${QT_MAJOR_VERSION}HttpServer_LIBRARIES})
 
 set(QtHttpServer_deps QtCore QtConcurrent QtNetwork QtWebSockets)
 
index 7504fafe4dcd04685b890f2285d85b9b41518c78..026a8758a11f994a1109c0e73ccf1b58aef1bf2d 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2022 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtHttpServer">
+<typesystem package="PySide6.QtHttpServer"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtConcurrent/typesystem_concurrent.xml" generate="no"/>
   <load-typesystem name="QtWebSockets/typesystem_websockets.xml" generate="no"/>
 
index a44896cdb75a8028ce34f5d081d4d3544962f09e..e35b7bd11adb91d50cef9f927433bf2da799ebbd 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2018 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtLocation">
+<typesystem package="PySide6.QtLocation"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
   <load-typesystem name="QtPositioning/typesystem_positioning.xml" generate="no"/>
   <object-type name="QGeoCodeReply">
index 9e39680e34a343a44919549eaee8e9a001562712..e40c5a2edd805ea02ef4aa957642effa6531a9d6 100644 (file)
@@ -29,9 +29,12 @@ ${QtMultimedia_GEN_DIR}/qmediatimerange_wrapper.cpp
 ${QtMultimedia_GEN_DIR}/qmediatimerange_interval_wrapper.cpp
 ${QtMultimedia_GEN_DIR}/qscreencapture_wrapper.cpp
 ${QtMultimedia_GEN_DIR}/qsoundeffect_wrapper.cpp
+${QtMultimedia_GEN_DIR}/qtvideo_wrapper.cpp
 ${QtMultimedia_GEN_DIR}/qvideoframe_wrapper.cpp
+${QtMultimedia_GEN_DIR}/qvideoframe_paintoptions_wrapper.cpp
 ${QtMultimedia_GEN_DIR}/qvideoframeformat_wrapper.cpp
 ${QtMultimedia_GEN_DIR}/qvideosink_wrapper.cpp
+${QtMultimedia_GEN_DIR}/qwavedecoder_wrapper.cpp
 ${QtMultimedia_GEN_DIR}/qwindowcapture_wrapper.cpp
 
 # module is always needed
@@ -50,11 +53,8 @@ set(QtMultimedia_include_dirs   ${QtMultimedia_SOURCE_DIR}
                                 ${QtNetwork_GEN_DIR})
 
 set(QtMultimedia_libraries  pyside6
-                            ${Qt${QT_MAJOR_VERSION}Multimedia_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                            )
+                            ${Qt${QT_MAJOR_VERSION}Multimedia_LIBRARIES})
+
 set(QtMultimedia_deps QtCore QtGui QtNetwork)
 
 create_pyside_module(NAME QtMultimedia
index e9b601b1816a6c9b29b6319fb7e88b6103d34b72..2791f695a1655841f60b81e8d197c0040d76c4d1 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2021 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtMultimedia">
+<typesystem package="PySide6.QtMultimedia"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
     <load-typesystem name="QtNetwork/typesystem_network.xml" generate="no"/>
         <enum-type name="Error"/>
         <enum-type name="State"/>
         <enum-type name="VolumeScale"/>
+        <inject-code class="target" position="end"
+                     file="../glue/qtmultimedia.cpp"
+                     snippet="qtaudio-namespace-compatibility-alias"/>
+    </namespace-type>
+
+    <namespace-type name="QtVideo" since="6.7">
+        <enum-type name="Rotation"/>
     </namespace-type>
 
     <value-type name="QAudioBuffer">
     <object-type name="QAudioOutput"/>
 
     <object-type name="QAudioSource">
-      <modify-function signature="start()">
+      <modify-function signature="start()" allow-thread="true">
         <modify-argument index="return">
           <define-ownership class="target" owner="c++"/>
         </modify-argument>
       </modify-function>
-      <modify-function signature="start(QIODevice*)">
+      <modify-function signature="start(QIODevice*)" allow-thread="true">
         <modify-argument index="1">
           <define-ownership class="target" owner="c++"/>
         </modify-argument>
       </modify-function>
+      <modify-function signature="stop()" allow-thread="true"/>
     </object-type>
 
     <object-type name="QAudioSink">
-      <modify-function signature="start()">
+      <modify-function signature="start()" allow-thread="true">
         <modify-argument index="return">
           <define-ownership class="target" owner="c++"/>
         </modify-argument>
       </modify-function>
-      <modify-function signature="start(QIODevice*)">
+      <modify-function signature="start(QIODevice*)" allow-thread="true">
         <modify-argument index="1">
           <define-ownership class="target" owner="c++"/>
         </modify-argument>
       </modify-function>
+      <modify-function signature="stop()" allow-thread="true"/>
     </object-type>
 
     <object-type name="QCamera">
           <inject-code file="../glue/qtmultimedia.cpp" snippet="qvideoframe-bits"/>
         </modify-function>
         <modify-function signature="bits(int)const" remove="all"/>
+        <value-type name="PaintOptions">
+            <enum-type name="PaintFlag" flags="PaintFlags"/>
+        </value-type>
     </value-type>
     <value-type name="QVideoFrameFormat" since="6.1">
         <enum-type name="ColorSpace" since="6.4"/>
         <enum-type name="YCbCrColorSpace"/>
     </value-type>
 
+    <object-type name="QWaveDecoder">
+        <!-- No implementation -->
+        <modify-function signature="setIODevice(QIODevice*)" remove="all"/>
+    </object-type>
+
     <object-type name="QWindowCapture" since="6.6">
         <enum-type name="Error"/>
     </object-type>
index e3d8ca0eae4248ca433de8a6404410b76a601386..c3988551e27aced93ba9e910a750bfa482416c08 100644 (file)
@@ -26,12 +26,8 @@ set(QtMultimediaWidgets_include_dirs ${QtMultimediaWidgets_SOURCE_DIR}
                                      ${QtMultimedia_GEN_DIR})
 
 set(QtMultimediaWidgets_libraries    pyside6
-                                     ${Qt${QT_MAJOR_VERSION}Multimedia_LIBRARIES}
-                                     ${Qt${QT_MAJOR_VERSION}MultimediaWidgets_LIBRARIES}
-                                     ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                                     ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                                     ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                                     ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES})
+                                     ${Qt${QT_MAJOR_VERSION}MultimediaWidgets_LIBRARIES})
+
 
 set(QtMultimediaWidgets_deps QtCore QtGui QtNetwork QtWidgets QtMultimedia)
 
index 8d53e743aa719ed6b61769c6388e7ac0b3ca80fc..05b4e2456bd8cd94332d717f7a5fae7809415522 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2021 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtMultimediaWidgets">
+<typesystem package="PySide6.QtMultimediaWidgets"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
   <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
   <load-typesystem name="QtMultimedia/typesystem_multimedia.xml" generate="no"/>
index 21974f92c4c17826e875e6f48adcbda21e15d168..529e2e86b5d35666143c12289525306b7add47f2 100644 (file)
@@ -18,6 +18,8 @@ ${QtNetwork_GEN_DIR}/qdnstextrecord_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qhostaddress_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qhostinfo_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qhstspolicy_wrapper.cpp
+${QtNetwork_GEN_DIR}/qhttp1configuration_wrapper.cpp
+${QtNetwork_GEN_DIR}/qhttpheaders_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qhttpmultipart_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qhttppart_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qhttp2configuration_wrapper.cpp
@@ -38,7 +40,10 @@ ${QtNetwork_GEN_DIR}/qnetworkproxyfactory_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qnetworkproxyquery_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qnetworkreply_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qnetworkrequest_wrapper.cpp
+${QtNetwork_GEN_DIR}/qnetworkrequestfactory_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qpassworddigestor_wrapper.cpp
+${QtNetwork_GEN_DIR}/qrestaccessmanager_wrapper.cpp
+${QtNetwork_GEN_DIR}/qrestreply_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qssl_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qsslcertificate_wrapper.cpp
 ${QtNetwork_GEN_DIR}/qsslcertificateextension_wrapper.cpp
@@ -80,7 +85,8 @@ if("dtls" IN_LIST QtNetwork_disabled_features)
 else()
     list(APPEND QtNetwork_SRC
          ${QtNetwork_GEN_DIR}/qdtls_wrapper.cpp
-         ${QtNetwork_GEN_DIR}/qdtlsclientverifier_wrapper.cpp)
+         ${QtNetwork_GEN_DIR}/qdtlsclientverifier_wrapper.cpp
+         ${QtNetwork_GEN_DIR}/qdtlsclientverifier_generatorparameters_wrapper.cpp)
     message(STATUS "Qt${QT_MAJOR_VERSION}Network: Adding DTLS classes")
 endif()
 
index fbbf7dfa849daff38cdffd0b566c2156b4f2b0af..4dc7c9b0a9ff5f16d49a918c8db4011a5394621b 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtNetwork">
+<typesystem package="PySide6.QtNetwork"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
 
     <rejection class="QTlsPrivate"/>
     </object-type>
     <object-type name="QDtlsClientVerifier">
         <configuration condition="QT_CONFIG(dtls)"/>
+        <value-type name="GeneratorParameters">
+            <configuration condition="QT_CONFIG(dtls)"/>
+        </value-type>
     </object-type>
 
     <value-type name="QHstsPolicy">
         <enum-type name="PolicyFlag" flags="PolicyFlags"/>
     </value-type>
+    <value-type name="QHttp1Configuration"/>
+    <value-type name="QHttpHeaders" since="6.7">
+        <enum-type name="WellKnownHeader"/>
+    </value-type>
     <object-type name="QHttpMultiPart">
         <enum-type name="ContentType"/>
     </object-type>
         <modify-function signature="put(const QNetworkRequest &amp;,QIODevice*)" allow-thread="yes"/>
         <modify-function signature="put(const QNetworkRequest &amp;,const QByteArray &amp;)" allow-thread="yes"/>
         <modify-function signature="sendCustomRequest(const QNetworkRequest &amp;,const QByteArray &amp;,QIODevice*)" allow-thread="yes" since="4.7"/>
+        <modify-function signature="setCache(QAbstractNetworkCache*)">
+            <modify-argument index="1">
+                <define-ownership class="target" owner="c++"/>
+            </modify-argument>
+        </modify-function>
         <modify-function signature="setCookieJar(QNetworkCookieJar*)">
             <modify-argument index="1">
                 <define-ownership class="target" owner="c++"/>
     </value-type>
 
     <value-type name="QHostInfo">
+        <inject-code class="native" position="beginning" file="../glue/qtnetwork.cpp"
+                     snippet="qhostinfo-lookuphost-functor"/>
         <enum-type name="HostInfoError"/>
         <add-function signature="lookupHost(const QString &amp;,PyCallable)">
             <inject-code class="target" position="beginning"
     </value-type>
     <value-type name="QNetworkRequest">
         <enum-type name="Attribute"/>
-        <enum-type name="LoadControl" since="4.7"/>
-        <enum-type name="Priority" since="4.7"/>
+        <enum-type name="LoadControl"/>
+        <enum-type name="Priority"/>
         <enum-type name="CacheLoadControl"/>
         <enum-type name="KnownHeaders"/>
         <enum-type name="RedirectPolicy"/>
         <enum-type name="TransferTimeoutConstant"/>
     </value-type>
-
+    <value-type name="QNetworkRequestFactory" since="6.7"/>
     <object-type name="QAbstractNetworkCache"/>
     <object-type name="QNetworkDiskCache"/>
     <value-type name="QNetworkCacheMetaData"/>
 
+    <object-type name="QRestAccessManager" since="6.7">
+        <inject-code class="native" position="beginning" file="../glue/qtnetwork.cpp"
+                     snippet="qrestaccessmanager-functor"/>
+
+        <add-function signature="deleteResource(QNetworkRequest@request@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-callback"/>
+        </add-function>
+
+        <add-function signature="get(QNetworkRequest@request@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-callback"/>
+        </add-function>
+        <add-function signature="get(QNetworkRequest@request@,QByteArray@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="get(QNetworkRequest@request@,QIODevice*@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="get(QNetworkRequest@request@,QJsonDocument@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+
+        <add-function signature="head(QNetworkRequest@request@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-callback"/>
+        </add-function>
+
+        <add-function signature="patch(QNetworkRequest@request@,QByteArray@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="patch(QNetworkRequest@request@,QIODevice*@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="patch(QNetworkRequest@request@,QJsonDocument@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="patch(QNetworkRequest@request@,QVariantMap@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+
+        <add-function signature="post(QNetworkRequest@request@,QByteArray@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="post(QNetworkRequest@request@,QHttpMultiPart*@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="post(QNetworkRequest@request@,QIODevice*@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="post(QNetworkRequest@request@,QJsonDocument@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="post(QNetworkRequest@request@,QVariantMap@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+
+        <add-function signature="put(QNetworkRequest@request@,QByteArray@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="put(QNetworkRequest@request@,QHttpMultiPart*@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="put(QNetworkRequest@request@,QIODevice*@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="put(QNetworkRequest@request@,QJsonDocument@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+        <add-function signature="put(QNetworkRequest@request@,QVariantMap@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-data-callback"/>
+        </add-function>
+
+        <add-function signature="sendCustomRequest(QNetworkRequest@request@,QByteArray@method@,QByteArray@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-method-data-callback"/>
+        </add-function>
+        <add-function signature="sendCustomRequest(QNetworkRequest@request@,QByteArray@method@,QHttpMultiPart*@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-method-data-callback"/>
+        </add-function>
+        <add-function signature="sendCustomRequest(QNetworkRequest@request@,QByteArray@method@,QIODevice*@data@,QObject*@context@,PyCallable*@slot@)"
+                      return-type="QNetworkReply*">
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestaccessmanager-method-data-callback"/>
+        </add-function>
+    </object-type>
+
+    <object-type name="QRestReply" since="6.7">
+        <add-function signature="readJson()" return-type="PyObject">
+            <modify-argument index="return"
+                             pyi-type="Tuple[Optional[PySide6.QtCore.QJsonDocument],PySide6.QtCore.QJsonParseError]"/>
+            <inject-code class="target" position="beginning" file="../glue/qtnetwork.cpp"
+                         snippet="qrestreply-readjson"/>
+        </add-function>
+    </object-type>
+
     <object-type name="QSctpServer">
         <configuration condition="QT_CONFIG(sctp)"/>
     </object-type>
index d1d5d408d1f650d492d713b2147a160502e8545a..4d9498e4d0281837c3520bdf307608a92366db6f 100644 (file)
@@ -26,8 +26,6 @@ set(QtNetworkAuth_include_dirs ${QtNetworkAuth_SOURCE_DIR}
                                ${QtNetworkAuth_GEN_DIR})
 
 set(QtNetworkAuth_libraries pyside6
-                            ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
                             ${Qt${QT_MAJOR_VERSION}NetworkAuth_LIBRARIES})
 
 set(QtNetworkAuth_deps QtNetwork)
index a46dd2fcae347b99518e21ec0a95e436e767454b..bedfc5a2875f12cf3a14ec8747a758d4b1c05890 100644 (file)
@@ -4,13 +4,16 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.QtNetworkAuth">
+<typesystem package="PySide6.QtNetworkAuth"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtNetwork/typesystem_network.xml" generate="no"/>
     <object-type name="QAbstractOAuth">
         <enum-type name="ContentType"/>
         <enum-type name="Error"/>
         <enum-type name="Stage"/>
         <enum-type name="Status"/>
+        <inject-code class="native" position="beginning" file="../glue/qtnetworkauth.cpp"
+                     snippet="qabstractoauth-lookuphost-functor"/>
         <modify-function signature="setReplyHandler(QAbstractOAuthReplyHandler*)">
             <modify-argument index="1">
                 <define-ownership class="target" owner="c++"/>
index 7ecb6e73a5593dd0429c5d7cbf1fd0848ebf01a5..b94249a55ac43e2ba20e55661508baaca8af71ce 100644 (file)
@@ -14,6 +14,7 @@ set(QtNfc_SRC
     ${QtNfc_GEN_DIR}/qndefnfcurirecord_wrapper.cpp
     ${QtNfc_GEN_DIR}/qnearfieldmanager_wrapper.cpp
     ${QtNfc_GEN_DIR}/qnearfieldtarget_wrapper.cpp
+    ${QtNfc_GEN_DIR}/qnearfieldtarget_requestid_wrapper.cpp
 # module is always needed
     ${QtNfc_GEN_DIR}/qtnfc_module_wrapper.cpp)
 
index 91d6119c4e6e8910f940d491cd33c4ba0a34fc01..b548227f08b8bd881adc48bfd8b402d1027d45c5 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2022 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtNfc">
+<typesystem package="PySide6.QtNfc"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <value-type name="QNdefFilter">
         <value-type name="Record"/>
@@ -27,6 +28,7 @@
         <enum-type name="AccessMethod" flags="AccessMethods"/>
         <enum-type name="Error"/>
         <enum-type name="Type"/>
+        <value-type name="RequestId"/>
     </object-type>
     <!-- QtNetwork is pulled in via QtNfcDepends. -->
     <suppress-warning text="^Scoped enum 'Q(Ocsp)|(Dtls).*' does not have a type entry.*$"/>
index a5ee6c6faac9e20d85e4b78a378777f95e8ff1f6..5bf8b5f3bf298f46051fd4cf28ef4c7bbf462067 100644 (file)
@@ -87,8 +87,6 @@ set(QtOpenGL_include_dirs   ${QtOpenGL_SOURCE_DIR}
                             ${QtOpenGL_GEN_DIR}
                             )
 set(QtOpenGL_libraries      pyside6
-                            ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
                             ${Qt${QT_MAJOR_VERSION}OpenGL_LIBRARIES})
 set(QtOpenGL_deps QtGui)
 
index 53bec0fda73db591b4c2d573d405d46e423e31b7..efbd16056f333906be70ea30f85f0e66cd288225 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2021 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtOpenGL">
+<typesystem package="PySide6.QtOpenGL"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no" />
   <load-typesystem name="QtGui/typesystem_gui.xml" generate="no" />
   <load-typesystem name="templates/opengl_common.xml" generate="no" />
   </object-type>
   <value-type name="QOpenGLFramebufferObjectFormat"/>
   <object-type name="QAbstractOpenGLFunctions"/>
-  <value-type  name="QOpenGLPixelTransferOptions"/>
+  <value-type name="QOpenGLPixelTransferOptions"/>
   <object-type name="QOpenGLShader">
     <enum-type name="ShaderTypeBit" flags="ShaderType"/>
   </object-type>
index 14f9afae3ad00555d85b719104c2b5840685add7..8c7386130cfed9432627b7c96e8a0fb403c9a5f0 100644 (file)
@@ -21,10 +21,6 @@ set(QtOpenGLWidgets_include_dirs ${QtOpenGLWidgets_SOURCE_DIR}
                                  ${QtOpenGLWidgets_GEN_DIR})
 
 set(QtOpenGLWidgets_libraries pyside6
-                              ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                              ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                              ${Qt${QT_MAJOR_VERSION}OpenGL_LIBRARIES}
-                              ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
                               ${Qt${QT_MAJOR_VERSION}OpenGLWidgets_LIBRARIES})
 
 set(QtOpenGLWidgets_deps QtOpenGL QtWidgets)
index 27dbd8b14ba619847e7b3e99e1fab05980cbc52a..1e308a3f2cc71efb8101e115d7525556b09df3cf 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2020 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtOpenGLWidgets">
+<typesystem package="PySide6.QtOpenGLWidgets"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no" />
   <load-typesystem name="QtGui/typesystem_gui.xml" generate="no" />
   <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no" />
index c058e9a5c55576ac4d85e39053381a8f1fbd9775..5b9c1457ddf37c974096c62a7d88b2010d5578da 100644 (file)
@@ -29,10 +29,7 @@ set(QtPdf_include_dirs ${QtPdf_SOURCE_DIR}
                        ${QtNetwork_GEN_DIR})
 
 set(QtPdf_libraries pyside6
-    ${Qt${QT_MAJOR_VERSION}Pdf_LIBRARIES}
-    ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-    ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-    ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES})
+                    ${Qt${QT_MAJOR_VERSION}Pdf_LIBRARIES})
 
 set(QtPdf_deps QtCore QtGui QtNetwork)
 
index 229421ad6ea31c800080c1c7f93b57cffb874ebf..e008e48803979a683bfe36abed8f06ce0c799d62 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2022 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtPdf">
+<typesystem package="PySide6.QtPdf"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
     <object-type name="QPdfBookmarkModel">
index 93ad3638dde61d1d88484029d5434624b1fd2a0b..de1335f8a90ab899623d0ea77ee878d96efea2df 100644 (file)
@@ -26,12 +26,7 @@ set(QtPdfWidgets_include_dirs ${QtPdfWidgets_SOURCE_DIR}
                               ${QtPdf_GEN_DIR})
 
 set(QtPdfWidgets_libraries pyside6
-    ${Qt${QT_MAJOR_VERSION}Pdf_LIBRARIES}
-    ${Qt${QT_MAJOR_VERSION}PdfWidgets_LIBRARIES}
-    ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-    ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-    ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-    ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES})
+                           ${Qt${QT_MAJOR_VERSION}PdfWidgets_LIBRARIES})
 
 set(QtPdfWidgets_deps QtCore QtGui QtNetwork QtWidgets QtPdf)
 
index 5f15e5ecb73b03b88fefcc4d0918018ec1a8331a..5df72075c8e11c10e4beed00d624dada2cb4d7f9 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2022 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtPdfWidgets">
+<typesystem package="PySide6.QtPdfWidgets"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
     <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
index d8622e682998caecf2ccdea1242aa5a891d08ae5..cad6dcb749f2b8c85a161329f83c92a5e43ce46b 100644 (file)
@@ -23,6 +23,7 @@ ${QtPositioning_GEN_DIR}/qgeosatelliteinfo_wrapper.cpp
 ${QtPositioning_GEN_DIR}/qgeosatelliteinfosource_wrapper.cpp
 ${QtPositioning_GEN_DIR}/qgeoshape_wrapper.cpp
 ${QtPositioning_GEN_DIR}/qnmeapositioninfosource_wrapper.cpp
+${QtPositioning_GEN_DIR}/qnmeasatelliteinfosource_wrapper.cpp
 # module is always needed
 ${QtPositioning_GEN_DIR}/qtpositioning_module_wrapper.cpp
 )
@@ -46,3 +47,14 @@ create_pyside_module(NAME QtPositioning
                      TYPESYSTEM_PATH QtPositioning_SOURCE_DIR
                      SOURCES QtPositioning_SRC
                      DROPPED_ENTRIES QtPositioning_DROPPED_ENTRIES)
+
+if (APPLE)
+    # The QtLocation permission plugin cannot be linked to QtCore.abi3.so because for a framework
+    # build of Qt, the QtCore framework bundle must be loaded before calling
+    # Q_IMPORT_PLUGIN(QDarwinLocationPermissionPlugin)
+    set(permission_plugin_name "QDarwinLocationPermissionPlugin")
+    set(permission_plugin "${QT_CMAKE_EXPORT_NAMESPACE}::${permission_plugin_name}")
+    set_target_properties(QtPositioning PROPERTIES "_qt_has_${permission_plugin_name}_usage_description" TRUE)
+    # importing the plugin
+    qt6_import_plugins(QtPositioning INCLUDE ${permission_plugin})
+endif()
index 359a7062d35f9f15b7403570c7deac4b460ab4c5..8dac3f00ddd5feaf0ec6acd5e4db7b4871ed9abe 100644 (file)
@@ -3,8 +3,11 @@
 // Copyright (C) 2018 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtPositioning">
+<typesystem package="PySide6.QtPositioning"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
+  <inject-code class="native" position="beginning" file="../glue/qtpositioning.cpp"
+               snippet="darwin_location_permission_plugin"/>
   <value-type name="QGeoAddress"/>
   <value-type name="QGeoAreaMonitorInfo"/>
   <object-type name="QGeoAreaMonitorSource">
@@ -41,4 +44,8 @@
   <object-type name="QNmeaPositionInfoSource">
       <enum-type name="UpdateMode"/>
   </object-type>
+  <object-type name="QNmeaSatelliteInfoSource">
+      <enum-type name="UpdateMode"/>
+      <enum-type name="SatelliteInfoParseStatus"/>
+  </object-type>
 </typesystem>
index 615d202fee070c17431d00a8548996fe6830c500..fb0db5f8372e74be173a39ce3ae62cdebcde4d5c 100644 (file)
@@ -25,14 +25,11 @@ set(QtPrintSupport_include_dirs ${QtPrintSupport_SOURCE_DIR}
                                 ${libpyside_SOURCE_DIR}
                                 ${QtCore_GEN_DIR}
                                 ${QtGui_GEN_DIR}
-                                ${QtWidgets_GEN_DIR}
-                                )
+                                ${QtWidgets_GEN_DIR})
+
 set(QtPrintSupport_libraries    pyside6
-                                ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                                ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                                ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
-                                ${Qt${QT_MAJOR_VERSION}PrintSupport_LIBRARIES}
-                                )
+                                ${Qt${QT_MAJOR_VERSION}PrintSupport_LIBRARIES})
+
 set(QtPrintSupport_deps QtWidgets)
 create_pyside_module(NAME QtPrintSupport
                      INCLUDE_DIRS QtPrintSupport_include_dirs
index 58d4a54b3426b913a81d490803ef61b4d4f1377e..46973a5f97b50d4a74a1f6707e0969bd76850d37 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtPrintSupport">
+<typesystem package="PySide6.QtPrintSupport"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
     <load-typesystem name="QtPrintSupport/typesystem_printsupport_common.xml" generate="yes"/>
 </typesystem>
index 676f55a257c7bd89fcc09713d7fe14143020b27e..87de1d7dd43b58f375bf0c27a0cd0f0b04f88e0a 100644 (file)
@@ -63,8 +63,6 @@ set(QtQml_include_dirs  ${QtQml_SOURCE_DIR}
                         ${QtQml_GEN_DIR})
 
 set(QtQml_libraries pyside6 pyside6qml
-                    ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                    ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
                     ${Qt${QT_MAJOR_VERSION}Qml_LIBRARIES})
 
 set(QtQml_deps QtNetwork)
index e92e13aaf32c23e6955b795cc102b650151a1bb7..ca3dfebeda5f06dc8f88121f2069158e08a17504 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "pysideqmlvolatilebool.h"
 
+#include <pep384ext.h>
 #include <signature.h>
 
 #include <QtCore/QDebug>
@@ -30,8 +31,7 @@ QtQml_VolatileBoolObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     if (ok < 0)
         return nullptr;
 
-    QtQml_VolatileBoolObject *self
-            = reinterpret_cast<QtQml_VolatileBoolObject *>(type->tp_alloc(type, 0));
+    auto *self = PepExt_TypeCallAlloc<QtQml_VolatileBoolObject>(type, 0);
 
     if (self != nullptr)
         self->flag = new AtomicBool(ok);
@@ -49,7 +49,10 @@ static void QtQml_VolatileBoolObject_dealloc(PyObject *self)
 static PyObject *
 QtQml_VolatileBoolObject_get(QtQml_VolatileBoolObject *self)
 {
-    return *self->flag ? Py_True : Py_False;
+    if (*self->flag) {
+        Py_RETURN_TRUE;
+    }
+    Py_RETURN_FALSE;
 }
 
 static PyObject *
@@ -63,10 +66,8 @@ QtQml_VolatileBoolObject_set(QtQml_VolatileBoolObject *self, PyObject *args)
     }
 
     ok = PyObject_IsTrue(value);
-    if (ok < 0) {
-        PyErr_SetString(PyExc_TypeError, "Not a boolean value.");
-        return nullptr;
-    }
+    if (ok < 0)
+        return PyErr_Format(PyExc_TypeError, "Not a boolean value.");
 
     *self->flag = ok > 0;
 
index b5538dcba4979967e8f32b89231894977a833bad..3392ef379ef19f3b5d70534c7490aa6b64c261f1 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtQml">
+<typesystem package="PySide6.QtQml"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <load-typesystem name="QtNetwork/typesystem_network.xml" generate="no"/>
 
@@ -37,7 +38,7 @@
              in generator tests folder. -->
     </primitive-type>
 
-    <enum-type name="QQmlModuleImportSpecialVersions"/>
+    <enum-type name="QQmlModuleImportSpecialVersions" doc-file="qqmlengine"/>
 
     <!-- expose QQmlIncubationController::incubateWhile() (see
          QtQml_VolatileBoolTypeF/pysideqmlvolatilebool.h) -->
 
     <add-function signature="qmlRegisterType(PyTypeObject@type_obj@,const char*@uri@,int@version_major@,int@version_minor@,const char*@qml_name@)" return-type="int">
         <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistertype"/>
+        <inject-documentation format="target" mode="append" file="../doc/qtqml_functions.rst"
+                              snippet="qmlregistertype"/>
         <modify-argument index="2" pyi-type="str"/>
     </add-function>
 
     <add-function signature="qmlRegisterSingletonType(PyTypeObject@type_obj@,const char*@uri@,int@version_major@,int@version_minor@,const char*@qml_name@,PyObject*@callback@)" return-type="int">
       <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletontype_qobject_callback"/>
+      <inject-documentation format="target" mode="append" file="../doc/qtqml_functions.rst"
+                            snippet="qmlregistersingletontype_qobject_callback"/>
       <modify-argument index="2" pyi-type="str"/>
     </add-function>
 
     <add-function signature="qmlRegisterSingletonType(PyTypeObject@type_obj@,const char*@uri@,int@version_major@,int@version_minor@,const char*@qml_name@)" return-type="int">
       <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletontype_qobject_nocallback"/>
+      <inject-documentation format="target" mode="append" file="../doc/qtqml_functions.rst"
+                            snippet="qmlregistersingletontype_qobject_nocallback"/>
       <modify-argument index="2" pyi-type="str"/>
     </add-function>
 
     <add-function signature="qmlRegisterSingletonType(const char*@uri@,int@version_major@,int@version_minor@,const char*@qml_name@,PyObject*@callback@)" return-type="int">
       <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletontype_qjsvalue"/>
+      <inject-documentation format="target" mode="append" file="../doc/qtqml_functions.rst"
+                            snippet="qmlregistersingletontype_qjsvalue"/>
       <modify-argument index="1" pyi-type="str"/>
     </add-function>
 
     <add-function signature="qmlRegisterSingletonInstance(PyTypeObject@type_obj@,const char*@uri@,int@version_major@,int@version_minor@,const char*@qml_name@,PyObject*@callback@)" return-type="int">
       <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletoninstance"/>
+      <inject-documentation format="target" mode="append" file="../doc/qtqml_functions.rst"
+                            snippet="qmlregistersingletoninstance"/>
       <modify-argument index="2" pyi-type="str"/>
     </add-function>
 
     <add-function signature="qmlRegisterUncreatableType(PyTypeObject@type_obj@,const char*@uri@,int@version_major@,int@version_minor@,const char*@qml_name@,const char*@message@)" return-type="int">
         <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregisteruncreatabletype"/>
+        <inject-documentation format="target" mode="append" file="../doc/qtqml_functions.rst"
+                              snippet="qmlregisteruncreatabletype"/>
         <modify-argument index="2" pyi-type="str"/>
     </add-function>
 
             <modify-argument index="return" pyi-type="Optional[PySide6.QtQml.QJSEngine]"/>
         </modify-function>
     </function>
-    <function signature="qmlClearTypeRegistrations()"/>
+    <function signature="qmlClearTypeRegistrations()" doc-file="qqmlengine"/>
     <function signature="qmlContext(const QObject*)">
         <modify-function>
             <modify-argument index="return" pyi-type="Optional[PySide6.QtQml.QQmlContext]"/>
             <modify-argument index="return" pyi-type="Optional[PySide6.QtQml.QQmlEngine]"/>
         </modify-function>
      </function>
-    <function signature="qmlProtectModule(const char*,int)"/>
-    <function signature="qmlRegisterModule(const char*,int,int)"/>
-    <function signature="qmlTypeId(const char*,int,int,const char*)"/>
-    <function signature="qmlRegisterType(const QUrl &amp;,const char *,int,int,const char *)"/>
-    <function signature="qmlRegisterSingletonType(const QUrl &amp;,const char *,int,int,const char *)"/>
-    <function signature="qmlRegisterUncreatableMetaObject(const QMetaObject&amp;,const char*,int,int, const char*,const QString&amp;)"/>
+    <function signature="qmlProtectModule(const char*,int)" doc-file="qqmlengine"/>
+    <function signature="qmlRegisterModule(const char*,int,int)" doc-file="qqmlengine"/>
+    <function signature="qmlTypeId(const char*,int,int,const char*)" doc-file="qqmlengine"/>
+    <function signature="qmlRegisterType(const QUrl &amp;,const char *,int,int,const char *)"
+              doc-file="qqmlengine"/>
+    <function signature="qmlRegisterSingletonType(const QUrl &amp;,const char *,int,int,const char *)"
+              doc-file="qqmlengine"/>
+    <function signature="qmlRegisterUncreatableMetaObject(const QMetaObject&amp;,const char*,int,int, const char*,const QString&amp;)"
+              doc-file="qqmlengine"/>
 
     <enum-type identified-by-value="QML_HAS_ATTACHED_PROPERTIES">
         <extra-includes>
             <modify-argument index="1"><replace-type modified-type="PyPathLike"/></modify-argument>
             <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qfile-path-1"/>
         </modify-function>
+        <add-function signature="singletonInstance(int@qmlTypeId@)"
+                      return-type="QObject*">
+            <!-- Suppress return value heuristics -->
+            <modify-argument index="return"
+                             pyi-type="Union[PySide6.QtCore.QObject, PySide6.QtQml.QJSValue, None]">
+                <define-ownership class="target" owner="default"/>
+            </modify-argument>
+            <inject-code class="target" file="../glue/qtqml.cpp"
+                         snippet="qqmlengine-singletoninstance-qmltypeid"/>
+            <inject-documentation format="target" mode="append" file="../doc/qtqml_functions.rst"
+                                  snippet="qqmlengine-singletoninstance-qmltypeid"/>
+        </add-function>
+        <add-function signature="singletonInstance(QString@uri@,QString@typeName@)"
+                      return-type="QObject*">
+            <!-- Suppress return value heuristics -->
+            <modify-argument index="return"
+                             pyi-type="Union[PySide6.QtCore.QObject, PySide6.QtQml.QJSValue, None]">
+                <define-ownership class="target" owner="default"/>
+            </modify-argument>
+            <inject-code class="target" file="../glue/qtqml.cpp"
+                         snippet="qqmlengine-singletoninstance-typename"/>
+            <inject-documentation format="target" mode="append" file="../doc/qtqml_functions.rst"
+                                  snippet="qqmlengine-singletoninstance-typename"/>
+        </add-function>
     </object-type>
 
     <object-type name="QQmlExpression">
index 497d318182dbb877cae61755c38b2e901e78f9cc..7752302428eee0c68180f0552c39f2b61851e6c3 100644 (file)
@@ -3,6 +3,8 @@
 
 project(QtQuick)
 
+set(QtQuick_DROPPED_ENTRIES)
+
 set(QtQuick_registerType "${QtQuick_SOURCE_DIR}/pysidequickregistertype.cpp")
 
 # Exclude sources that have clashing static helper functions named "renderstate_..."
@@ -17,8 +19,6 @@ set_property(SOURCE ${QtQuick_SRC_UNITY_EXCLUDED_SRC}
 set(QtQuick_SRC
 ${QtQuick_SRC_UNITY_EXCLUDED_SRC}
 ${QtQuick_GEN_DIR}/qquickasyncimageprovider_wrapper.cpp
-${QtQuick_GEN_DIR}/qquickframebufferobject_wrapper.cpp
-${QtQuick_GEN_DIR}/qquickframebufferobject_renderer_wrapper.cpp
 ${QtQuick_GEN_DIR}/qquickgraphicsconfiguration_wrapper.cpp
 ${QtQuick_GEN_DIR}/qquickgraphicsdevice_wrapper.cpp
 ${QtQuick_GEN_DIR}/qquicktexturefactory_wrapper.cpp
@@ -32,9 +32,12 @@ ${QtQuick_GEN_DIR}/qsharedpointer_qquickitemgrabresult_wrapper.cpp
 ${QtQuick_GEN_DIR}/qquickpainteditem_wrapper.cpp
 ${QtQuick_GEN_DIR}/qquickrendercontrol_wrapper.cpp
 ${QtQuick_GEN_DIR}/qquickrendertarget_wrapper.cpp
+${QtQuick_GEN_DIR}/qquickrhiitemrenderer_wrapper.cpp
+${QtQuick_GEN_DIR}/qquickrhiitem_wrapper.cpp
 ${QtQuick_GEN_DIR}/qquicktextdocument_wrapper.cpp
 ${QtQuick_GEN_DIR}/qquickview_wrapper.cpp
 ${QtQuick_GEN_DIR}/qquickwindow_wrapper.cpp
+${QtQuick_GEN_DIR}/qquickwindow_graphicsstateinfo_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgbasicgeometrynode_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgclipnode_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgdynamictexture_wrapper.cpp
@@ -46,19 +49,25 @@ ${QtQuick_GEN_DIR}/qsggeometry_point2d_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsggeometry_texturedpoint2d_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsggeometry_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsggeometrynode_wrapper.cpp
+${QtQuick_GEN_DIR}/qsgimagenode_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgmaterial_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgmaterialshader_wrapper.cpp
+${QtQuick_GEN_DIR}/qsgmaterialshader_graphicspipelinestate_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgmaterialtype_wrapper.cpp
+${QtQuick_GEN_DIR}/qsgninepatchnode_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgnode_wrapper.cpp
+${QtQuick_GEN_DIR}/qsgnodevisitor_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgopacitynode_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgopaquetexturematerial_wrapper.cpp
 #${QtQuick_GEN_DIR}/qsgsimplematerial_wrapper.cpp
 #${QtQuick_GEN_DIR}/qsgsimplematerialshader_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgrectanglenode_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgrendernode_wrapper.cpp
+${QtQuick_GEN_DIR}/qsgrootnode_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgsimplerectnode_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgsimpletexturenode_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgrendererinterface_wrapper.cpp
+${QtQuick_GEN_DIR}/qsgtextnode_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgtexture_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgtexturematerial_wrapper.cpp
 ${QtQuick_GEN_DIR}/qsgtextureprovider_wrapper.cpp
@@ -73,28 +82,32 @@ set(QtQuick_include_dirs  ${QtQuick_SOURCE_DIR}
                           ${Qt${QT_MAJOR_VERSION}Core_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Core_PRIVATE_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Gui_INCLUDE_DIRS}
-                          ${Qt${QT_MAJOR_VERSION}OpenGL_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Network_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Qml_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Qml_PRIVATE_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Quick_INCLUDE_DIRS}
                           ${libpyside_SOURCE_DIR}
                           ${QtGui_GEN_DIR}
-                          ${QtOpenGL_GEN_DIR}
                           ${QtCore_GEN_DIR}
                           ${QtNetwork_GEN_DIR}
                           ${QtQml_GEN_DIR}
                           ${QtQuick_GEN_DIR})
 
 set(QtQuick_libraries pyside6 pyside6qml
-                      ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}OpenGL_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Qml_LIBRARIES}
                       ${Qt${QT_MAJOR_VERSION}Quick_LIBRARIES})
 
-set(QtQuick_deps QtGui QtOpenGL QtNetwork QtQml)
+set(QtQuick_deps QtGui QtNetwork QtQml)
+
+check_qt_opengl("Quick" QtQuick_include_dirs QtQuick_deps
+                QtQuick_DROPPED_ENTRIES)
+
+if (Qt${QT_MAJOR_VERSION}OpenGL_FOUND)
+    list(APPEND QtQuick_SRC
+         ${QtQuick_GEN_DIR}/qquickframebufferobject_wrapper.cpp
+         ${QtQuick_GEN_DIR}/qquickframebufferobject_renderer_wrapper.cpp)
+else()
+    list(APPEND QtQuick_DROPPED_ENTRIES QQuickFramebufferObject)
+endif()
 
 create_pyside_module(NAME QtQuick
                      INCLUDE_DIRS QtQuick_include_dirs
@@ -102,4 +115,5 @@ create_pyside_module(NAME QtQuick
                      DEPS QtQuick_deps
                      TYPESYSTEM_PATH QtQuick_SOURCE_DIR
                      SOURCES QtQuick_SRC
-                     STATIC_SOURCES QtQuick_registerType)
+                     STATIC_SOURCES QtQuick_registerType
+                     DROPPED_ENTRIES QtQuick_DROPPED_ENTRIES)
index f15e1f3d5321a3b8ee45e9e918e470ba1a010b23..f7749b4e71b5a95b222829c243f73a1848ae7048 100644 (file)
@@ -9,7 +9,10 @@
 #include <shiboken.h>
 
 #include <QtQuick/QQuickPaintedItem>
-#include <QtQuick/QQuickFramebufferObject>
+
+#if QT_CONFIG(opengl) || QT_CONFIG(opengles2) || QT_CONFIG(opengles3)
+#  include <QtQuick/QQuickFramebufferObject>
+#endif
 
 bool pyTypeObjectInheritsFromClass(PyTypeObject *pyObjType, const char *classPtrName)
 {
@@ -22,7 +25,7 @@ bool pyTypeObjectInheritsFromClass(PyTypeObject *pyObjType, const char *classPtr
 template <class WrappedClass>
 bool registerTypeIfInheritsFromClass(const char *classPtrName,
                                      PyTypeObject *typeToRegister,
-                                     QQmlPrivate::RegisterType *type)
+                                     QQmlPrivate::RegisterTypeAndRevisions *type)
 {
     if (!pyTypeObjectInheritsFromClass(typeToRegister, classPtrName))
         return false;
@@ -35,7 +38,7 @@ bool registerTypeIfInheritsFromClass(const char *classPtrName,
     return true;
 }
 
-bool quickRegisterType(PyObject *pyObj, QQmlPrivate::RegisterType *type)
+bool quickRegisterType(PyObject *pyObj, QQmlPrivate::RegisterTypeAndRevisions *type)
 {
     using namespace Shiboken;
 
@@ -51,8 +54,10 @@ bool quickRegisterType(PyObject *pyObj, QQmlPrivate::RegisterType *type)
 
     return registerTypeIfInheritsFromClass<QQuickPaintedItem>("QQuickPaintedItem*",
                                                               pyObjType, type)
+#if QT_CONFIG(opengl) || QT_CONFIG(opengles2) || QT_CONFIG(opengles3)
         || registerTypeIfInheritsFromClass<QQuickFramebufferObject>("QQuickFramebufferObject*",
                                                                     pyObjType, type)
+#endif
         || registerTypeIfInheritsFromClass<QQuickItem>("QQuickItem*",
                                                        pyObjType, type);
 }
@@ -62,7 +67,9 @@ void PySide::initQuickSupport(PyObject *module)
     Q_UNUSED(module);
     // We need to manually register a pointer version of these types in order for them to be used as property types.
     qRegisterMetaType<QQuickPaintedItem*>("QQuickPaintedItem*");
+#if QT_CONFIG(opengl) || QT_CONFIG(opengles2) || QT_CONFIG(opengles3)
     qRegisterMetaType<QQuickFramebufferObject*>("QQuickFramebufferObject*");
+#endif
     qRegisterMetaType<QQuickItem*>("QQuickItem*");
 
     Qml::setQuickRegisterItemFunction(quickRegisterType);
index a7f5ec492a7ea120fda8dbc20a7eefd8b3ea9adb..0a24123f4d1b0aa1dfa381f4dd04a1b42e38e160 100644 (file)
@@ -3,11 +3,15 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtQuick">
+<typesystem package="PySide6.QtQuick"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <load-typesystem name="QtNetwork/typesystem_network.xml" generate="no"/>
+    <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
     <!-- QQuickFramebufferObject::Renderer needs QOpenGLFramebufferObject -->
+    <?if !no_QtOpenGL?>
     <load-typesystem name="QtOpenGL/typesystem_opengl.xml" generate="no"/>
+    <?endif?>
     <load-typesystem name="QtQml/typesystem_qml.xml" generate="no"/>
 
     <smart-pointer-type name="QSharedPointer" type="shared" getter="data"
         <!-- TODO: Find a way to wrap `union ItemChangeData {}` -->
     </object-type>
 
+    <object-type name="QQuickRhiItemRenderer" since="6.7"/>
+    <object-type name="QQuickRhiItem" since="6.7">
+        <enum-type name="TextureFormat"/>
+    </object-type>
+
     <object-type name="QQuickItemGrabResult"/>
 
     <object-type name="QQuickPaintedItem">
@@ -89,7 +98,9 @@
         <modify-function signature="^fromVulkanImage\(.*$" remove="all"/>
     </value-type>
 
-    <object-type name="QQuickTextDocument"/>
+    <object-type name="QQuickTextDocument">
+        <enum-type name="Status" since="6.7"/>
+    </object-type>
 
     <object-type name="QQuickView">
         <enum-type name="ResizeMode"/>
         <enum-type name="RenderStage"/>
         <enum-type name="SceneGraphError"/>
         <enum-type name="TextRenderType"/>
+        <value-type name="GraphicsStateInfo"/>
     </object-type>
 
     <object-type name="QSGBasicGeometryNode">
         </modify-function>
     </object-type>
 
+    <object-type name="QSGImageNode">
+        <enum-type name="TextureCoordinatesTransformFlag" flags="TextureCoordinatesTransformMode"/>
+    </object-type>
+
     <object-type name="QSGMaterial">
         <enum-type name="Flag" flags="Flags"/>
     </object-type>
         <value-type name="RenderState">
             <enum-type name="DirtyState" flags="DirtyStates"/>
         </value-type>
+        <value-type name="GraphicsPipelineState">
+            <enum-type name="BlendFactor"/>
+            <enum-type name="ColorMaskComponent" flags="ColorMask"/>
+            <enum-type name="CullMode"/>
+            <enum-type name="PolygonMode"/>
+        </value-type>
         <modify-function signature="updateSampledImage(QSGMaterialShader::RenderState&amp;,int,QSGTexture**,QSGMaterial*,QSGMaterial*)" remove="all"/>
         <!-- Private QRhi class -->
         <modify-function signature="setShader(QSGMaterialShader::Stage,QShader)" remove="all"/>
     </object-type>
     <object-type name="QSGMaterialType"/>
+    <object-type name="QSGNinePatchNode"/>
     <object-type name="QSGNode">
         <enum-type name="DirtyStateBit" flags="DirtyState"/>
         <enum-type name="Flag" flags="Flags"/>
         <enum-type name="NodeType"/>
     </object-type>
+    <object-type name="QSGNodeVisitor"/>
+
     <object-type name="QSGOpacityNode"/>
     <object-type name="QSGOpaqueTextureMaterial"/>
     <object-type name="QSGSimpleRectNode"/>
     <object-type name="QSGSimpleTextureNode">
         <enum-type name="TextureCoordinatesTransformFlag" flags="TextureCoordinatesTransformMode"/>
     </object-type>
+    <object-type name="QSGTextNode" since="6.7">
+        <enum-type name="TextStyle"/>
+        <enum-type name="RenderType"/>
+    </object-type>
     <object-type name="QSGRectangleNode"/>
     <object-type name="QSGRendererInterface">
         <enum-type name="GraphicsApi"/>
         <enum-type name="RenderingFlag" flags="RenderingFlags"/>
         <object-type name="RenderState"/>
     </object-type>
+    <object-type name="QSGRootNode"/>
     <object-type name="QSGTexture">
         <enum-type name="AnisotropyLevel"/>
         <enum-type name="Filtering"/>
index b98a1dd1e43f9f5cf7526efe8eb1c315ef09623b..37f8ebfb195abc6c6407f9d238cdbf01acc6bf6f 100644 (file)
@@ -3,6 +3,8 @@
 
 project(QtQuick3D)
 
+set (QtQuick3D_DROPPED_ENTRIES)
+
 set(QtQuick3D_SRC
 ${QtQuick3D_GEN_DIR}/qquick3d_wrapper.cpp
 ${QtQuick3D_GEN_DIR}/qquick3dobject_wrapper.cpp
@@ -11,6 +13,7 @@ ${QtQuick3D_GEN_DIR}/qquick3dgeometry_attribute_wrapper.cpp
 ${QtQuick3D_GEN_DIR}/qquick3dgeometry_targetattribute_wrapper.cpp
 ${QtQuick3D_GEN_DIR}/qquick3dinstancing_wrapper.cpp
 ${QtQuick3D_GEN_DIR}/qquick3dinstancing_instancetableentry_wrapper.cpp
+${QtQuick3D_GEN_DIR}/qquick3drenderextension_wrapper.cpp
 ${QtQuick3D_GEN_DIR}/qquick3dtexturedata_wrapper.cpp
 # module is always needed
 ${QtQuick3D_GEN_DIR}/qtquick3d_module_wrapper.cpp
@@ -21,7 +24,6 @@ set(QtQuick3D_include_dirs  ${QtQuick3D_SOURCE_DIR}
                           ${Qt${QT_MAJOR_VERSION}Core_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Core_PRIVATE_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Gui_INCLUDE_DIRS}
-                          ${Qt${QT_MAJOR_VERSION}OpenGL_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Network_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Qml_INCLUDE_DIRS}
                           ${Qt${QT_MAJOR_VERSION}Qml_PRIVATE_INCLUDE_DIRS}
@@ -29,7 +31,6 @@ set(QtQuick3D_include_dirs  ${QtQuick3D_SOURCE_DIR}
                           ${Qt${QT_MAJOR_VERSION}Quick3D_INCLUDE_DIRS}
                           ${libpyside_SOURCE_DIR}
                           ${QtGui_GEN_DIR}
-                          ${QtOpenGL_GEN_DIR}
                           ${QtCore_GEN_DIR}
                           ${QtNetwork_GEN_DIR}
                           ${QtQml_GEN_DIR}
@@ -37,19 +38,17 @@ set(QtQuick3D_include_dirs  ${QtQuick3D_SOURCE_DIR}
                           ${QtQuick3D_GEN_DIR})
 
 set(QtQuick3D_libraries pyside6
-                      ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}OpenGL_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Qml_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Quick_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Quick3D_LIBRARIES})
+                        ${Qt${QT_MAJOR_VERSION}Quick3D_LIBRARIES})
+
+set(QtQuick3D_deps QtGui QtNetwork QtQml QtQuick)
 
-set(QtQuick3D_deps QtGui QtOpenGL QtNetwork QtQml QtQuick)
+check_qt_opengl("Quick3D" QtQuick3D_include_dirs QtQuick3D_deps
+                QtQuick3D_DROPPED_ENTRIES)
 
 create_pyside_module(NAME QtQuick3D
     INCLUDE_DIRS QtQuick3D_include_dirs
     LIBRARIES QtQuick3D_libraries
     DEPS QtQuick3D_deps
     TYPESYSTEM_PATH QtQuick3D_SOURCE_DIR
-    SOURCES QtQuick3D_SRC)
+    SOURCES QtQuick3D_SRC
+    DROPPED_ENTRIES QtQuick3D_DROPPED_ENTRIES)
index 274272bc2c5ad78b19c54a2962941972232cacda..fe8f4e700ee1f4c6863b841b6d25dda1068b7c49 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2021 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtQuick3D">
+<typesystem package="PySide6.QtQuick3D"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtQuick/typesystem_quick.xml" generate="no"/>
 
     <object-type name="QQuick3D"/>
@@ -25,4 +26,5 @@
     <object-type name="QQuick3DTextureData">
         <enum-type name="Format"/>
     </object-type>
+    <object-type name="QQuick3DRenderExtension" since="6.7"/>
 </typesystem>
index 0ba33b5ff15c6ce9c6e168b48ee90815e01bdb5e..9951d2e1e72720045f62accd768efefbfdbbf394 100644 (file)
@@ -3,8 +3,11 @@
 
 project(QtQuickControls2)
 
+set (QtQuickControls2_DROPPED_ENTRIES)
+
 set(QtQuickControls2_SRC
 ${QtQuickControls2_GEN_DIR}/qquickstyle_wrapper.cpp
+${QtQuickControls2_GEN_DIR}/qquickattachedpropertypropagator_wrapper.cpp
 # module is always needed
 ${QtQuickControls2_GEN_DIR}/qtquickcontrols2_module_wrapper.cpp
 )
@@ -14,14 +17,12 @@ set(QtQuickControls2_include_dirs ${QtQuickControls2_SOURCE_DIR}
                                   ${QtQml_SOURCE_DIR}
                                   ${Qt${QT_MAJOR_VERSION}Core_INCLUDE_DIRS}
                                   ${Qt${QT_MAJOR_VERSION}Gui_INCLUDE_DIRS}
-                                  ${Qt${QT_MAJOR_VERSION}OpenGL_INCLUDE_DIRS}
                                   ${Qt${QT_MAJOR_VERSION}Network_INCLUDE_DIRS}
                                   ${Qt${QT_MAJOR_VERSION}Qml_INCLUDE_DIRS}
                                   ${Qt${QT_MAJOR_VERSION}Quick_INCLUDE_DIRS}
                                   ${Qt${QT_MAJOR_VERSION}QuickControls2_INCLUDE_DIRS}
                                   ${libpyside_SOURCE_DIR}
                                   ${QtGui_GEN_DIR}
-                                  ${QtOpenGL_GEN_DIR}
                                   ${QtCore_GEN_DIR}
                                   ${QtNetwork_GEN_DIR}
                                   ${QtQml_GEN_DIR}
@@ -29,19 +30,17 @@ set(QtQuickControls2_include_dirs ${QtQuickControls2_SOURCE_DIR}
                                   ${QtQuickControls2_GEN_DIR})
 
 set(QtQuickControls2_libraries pyside6
-                      ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}OpenGL_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Qml_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}Quick_LIBRARIES}
-                      ${Qt${QT_MAJOR_VERSION}QuickControls2_LIBRARIES})
+                               ${Qt${QT_MAJOR_VERSION}QuickControls2_LIBRARIES})
+
+set(QtQuickControls2_deps QtGui QtNetwork QtQml QtQuick)
 
-set(QtQuickControls2_deps QtGui QtOpenGL QtNetwork QtQml QtQuick)
+check_qt_opengl("QuickControls2" QtQuickControls2_include_dirs QtQuickControls2_deps
+                QtQuickControls2_DROPPED_ENTRIES)
 
 create_pyside_module(NAME QtQuickControls2
                      INCLUDE_DIRS QtQuickControls2_include_dirs
                      LIBRARIES QtQuickControls2_libraries
                      DEPS QtQuickControls2_deps
                      TYPESYSTEM_PATH QtQuickControls2_SOURCE_DIR
-                     SOURCES QtQuickControls2_SRC)
+                     SOURCES QtQuickControls2_SRC
+                     DROPPED_ENTRIES QtQuickControls2_DROPPED_ENTRIES)
index fa886b06f9f0a82c2c1b69746d3717f9d7b02ec7..72fc05226910367cf2f037f043f4aae2651a884e 100644 (file)
@@ -3,9 +3,11 @@
 // Copyright (C) 2020 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtQuickControls2">
+<typesystem package="PySide6.QtQuickControls2"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtQuick/typesystem_quick.xml" generate="no"/>
 
     <object-type name="QQuickStyle"/>
+    <object-type name="QQuickAttachedPropertyPropagator"/>
 
 </typesystem>
diff --git a/sources/pyside6/PySide6/QtQuickTest/CMakeLists.txt b/sources/pyside6/PySide6/QtQuickTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8e3fb4d
--- /dev/null
@@ -0,0 +1,44 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+project(QtQuickTest)
+
+set (QtQuickTest_DROPPED_ENTRIES)
+
+set(QtQuickTest_SRC
+# module is always needed
+${QtQuickTest_GEN_DIR}/qtquicktest_module_wrapper.cpp
+)
+
+set(QtQuickTest_include_dirs ${QtQuickTest_SOURCE_DIR}
+                             ${QtQml_SOURCE_DIR}
+                             ${Qt${QT_MAJOR_VERSION}Core_INCLUDE_DIRS}
+                             ${Qt${QT_MAJOR_VERSION}Gui_INCLUDE_DIRS}
+                             ${Qt${QT_MAJOR_VERSION}OpenGL_INCLUDE_DIRS}
+                             ${Qt${QT_MAJOR_VERSION}Network_INCLUDE_DIRS}
+                             ${Qt${QT_MAJOR_VERSION}Qml_INCLUDE_DIRS}
+                             ${Qt${QT_MAJOR_VERSION}Quick_INCLUDE_DIRS}
+                             ${libpyside_SOURCE_DIR}
+                             ${QtGui_GEN_DIR}
+                             ${QtOpenGL_GEN_DIR}
+                             ${QtCore_GEN_DIR}
+                             ${QtNetwork_GEN_DIR}
+                             ${QtQml_GEN_DIR}
+                             ${QtQuick_GEN_DIR}
+                             ${QtQuickTest_GEN_DIR})
+
+set(QtQuickTest_libraries pyside6
+                          ${Qt${QT_MAJOR_VERSION}QuickTest_LIBRARIES})
+
+set(QtQuickTest_deps QtGui QtNetwork QtQml QtQuick)
+
+check_qt_opengl("QuickTest" QtQuickTest_include_dirs QtQuickTest_deps
+                QtQuickTest_DROPPED_ENTRIES)
+
+create_pyside_module(NAME QtQuickTest
+                     INCLUDE_DIRS QtQuickTest_include_dirs
+                     LIBRARIES QtQuickTest_libraries
+                     DEPS QtQuickTest_deps
+                     TYPESYSTEM_PATH QtQuickTest_SOURCE_DIR
+                     SOURCES QtQuickTest_SRC
+                     DROPPED_ENTRIES QtQuickTest_DROPPED_ENTRIES)
diff --git a/sources/pyside6/PySide6/QtQuickTest/typesystem_quicktest.xml b/sources/pyside6/PySide6/QtQuickTest/typesystem_quicktest.xml
new file mode 100644 (file)
index 0000000..b6ef754
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+-->
+<typesystem package="PySide6.QtQuickTest"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
+    <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
+
+    <extra-includes>
+        <include file-name="QtQuickTest/quicktest.h" location="global"/>
+        <include file-name="QtCore/QDir" location="global"/>
+        <include file-name="pysideqobject.h" location="global"/>
+        <include file-name="vector" location="global"/>
+    </extra-includes>
+    <inject-code class="native" position="beginning"
+                 file="../glue/qtquicktest.cpp" snippet="call-quick-test-main"/>
+
+    <add-function signature="QUICK_TEST_MAIN(QString@name@,QStringList@argv@={},QString@dir@={})"
+                  return-type="int">
+        <inject-code file="../glue/qtquicktest.cpp" snippet="quick-test-main"/>
+        <inject-documentation format="target" mode="append"
+                              file="../doc/qtquicktest.rst"
+                              snippet="quick_test_main_documentation"/>
+    </add-function>
+    <add-function signature="QUICK_TEST_MAIN_WITH_SETUP(QString@name@,PyTypeObject*@setup@,QStringList@argv@={},QString@dir@={})"
+                  return-type="int">
+        <inject-code file="../glue/qtquicktest.cpp" snippet="quick-test-main_with_setup"/>
+        <inject-documentation format="target" mode="append"
+                              file="../doc/qtquicktest.rst"
+                              snippet="quick_test_main_with_setup_documentation"/>
+    </add-function>
+</typesystem>
index bab2fa5b0e991397286866b4638d6dcb7a8995e2..883010beed6d865a0c476387784b44cc0e2a326d 100644 (file)
@@ -3,6 +3,8 @@
 
 project(QtQuickWidgets)
 
+set (QtQuickWidgets_DROPPED_ENTRIES)
+
 set(QtQuickWidgets_SRC
 ${QtQuickWidgets_GEN_DIR}/qquickwidget_wrapper.cpp
 # module is always needed
@@ -30,20 +32,17 @@ set(QtQuickWidgets_include_dirs  ${QtQuickWidgets_SOURCE_DIR}
                                  ${QtQuickWidgets_GEN_DIR})
 
 set(QtQuickWidgets_libraries pyside6
-                             ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                             ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                             ${Qt${QT_MAJOR_VERSION}OpenGL_LIBRARIES}
-                             ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                             ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
-                             ${Qt${QT_MAJOR_VERSION}Quick_LIBRARIES}
-                             ${Qt${QT_MAJOR_VERSION}Qml_LIBRARIES}
                              ${Qt${QT_MAJOR_VERSION}QuickWidgets_LIBRARIES})
 
-set(QtQuickWidgets_deps QtGui QtOpenGL QtQml QtQuick QtWidgets QtNetwork)
+set(QtQuickWidgets_deps QtGui QtQml QtQuick QtWidgets QtNetwork)
+
+check_qt_opengl("QuickWidgets" QtQuickWidgets_include_dirs QtQuickWidgets_deps
+                QtQuickWidgets_DROPPED_ENTRIES)
 
 create_pyside_module(NAME QtQuickWidgets
                      INCLUDE_DIRS QtQuickWidgets_include_dirs
                      LIBRARIES QtQuickWidgets_libraries
                      DEPS QtQuickWidgets_deps
                      TYPESYSTEM_PATH QtQuickWidgets_SOURCE_DIR
-                     SOURCES QtQuickWidgets_SRC)
+                     SOURCES QtQuickWidgets_SRC
+                     DROPPED_ENTRIES QtQuickWidgets_DROPPED_ENTRIES)
index 2768e73d87900fa7ca389e3fa27635180fc2ac71..4f4484cb0aa7c3ec4c04849c72127106b538e0f4 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtQuickWidgets">
+<typesystem package="PySide6.QtQuickWidgets"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
     <load-typesystem name="QtQuick/typesystem_quick.xml" generate="no"/>
index f61bddf8a7f5dee0a9398522c1cd6781e832dbb7..07835b2f6d83e871481935ec890290475b1b73fe 100644 (file)
@@ -5,6 +5,7 @@ project(QtRemoteObjects)
 
 set(QtRemoteObjects_SRC
 ${QtRemoteObjects_GEN_DIR}/qabstractitemmodelreplica_wrapper.cpp
+${QtRemoteObjects_GEN_DIR}/qconnectionabstractserver_wrapper.cpp
 ${QtRemoteObjects_GEN_DIR}/qremoteobjectabstractpersistedstore_wrapper.cpp
 ${QtRemoteObjects_GEN_DIR}/qremoteobjectdynamicreplica_wrapper.cpp
 ${QtRemoteObjects_GEN_DIR}/qremoteobjecthost_wrapper.cpp
@@ -15,9 +16,14 @@ ${QtRemoteObjects_GEN_DIR}/qremoteobjectpendingcallwatcher_wrapper.cpp
 ${QtRemoteObjects_GEN_DIR}/qremoteobjectregistry_wrapper.cpp
 ${QtRemoteObjects_GEN_DIR}/qremoteobjectregistryhost_wrapper.cpp
 ${QtRemoteObjects_GEN_DIR}/qremoteobjectreplica_wrapper.cpp
-${QtRemoteObjects_GEN_DIR}/qtremoteobjects_wrapper.cpp
+${QtRemoteObjects_GEN_DIR}/qtremoteobjects_wrapper.cpp
 ${QtRemoteObjects_GEN_DIR}/qremoteobjectsettingsstore_wrapper.cpp
 ${QtRemoteObjects_GEN_DIR}/qremoteobjectsourcelocationinfo_wrapper.cpp
+${QtRemoteObjects_GEN_DIR}/qtroclientfactory_wrapper.cpp
+${QtRemoteObjects_GEN_DIR}/qtroclientiodevice_wrapper.cpp
+${QtRemoteObjects_GEN_DIR}/qtroiodevicebase_wrapper.cpp
+${QtRemoteObjects_GEN_DIR}/qtroserverfactory_wrapper.cpp
+${QtRemoteObjects_GEN_DIR}/qtroserveriodevice_wrapper.cpp
 
 # module is always needed
 ${QtRemoteObjects_GEN_DIR}/qtremoteobjects_module_wrapper.cpp
@@ -29,11 +35,10 @@ set(QtRemoteObjects_include_dirs ${QtRemoteObjects_SOURCE_DIR}
                                  ${SHIBOKEN_INCLUDE_DIR}
                                  ${libpyside_SOURCE_DIR}
                                  ${SHIBOKEN_PYTHON_INCLUDE_DIR}
-                                 ${QtCore_GEN_DIR})
+                                 ${QtCore_GEN_DIR}
+                                 ${QtNetwork_GEN_DIR})
 
 set(QtRemoteObjects_libraries    pyside6
-                                 ${SHIBOKEN_PYTHON_LIBRARIES}
-                                 ${SHIBOKEN_LIBRARY}
                                  ${Qt${QT_MAJOR_VERSION}RemoteObjects_LIBRARIES})
 
 set(QtRemoteObjects_deps QtCore QtNetwork)
index 0926b9b2516aa0f2f0bd470e8f1bac2d09be7e7e..86e4d90939bf5224c97dda77061cdf5330c82646 100644 (file)
@@ -3,20 +3,21 @@
 // Copyright (C) 2019 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtRemoteObjects">
+<typesystem package="PySide6.QtRemoteObjects"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="templates/core_common.xml" generate="no"/>
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
+    <load-typesystem name="QtNetwork/typesystem_network.xml" generate="no"/>
 
     <rejection class="QRemoteObjectStringLiterals"/>
     <rejection class="*" function-name="getTypeNameAndMetaobjectFromClassInfo"/>
-<!-- Exclude namespace due to Q_NAMESPACE link errors on Windows (QTBUG-68014)
     <rejection class="QtRemoteObjects" field-name="staticMetaObject"/>
     <namespace-type name="QtRemoteObjects">
         <enum-type name="InitialAction"/>
         <enum-type name="QRemoteObjectPacketTypeEnum"/>
     </namespace-type>
--->
     <object-type name="QAbstractItemModelReplica"/>
+    <object-type name="QConnectionAbstractServer"/>
     <object-type name="QRemoteObjectAbstractPersistedStore"/>
     <object-type name="QRemoteObjectDynamicReplica"/>
     <object-type name="QRemoteObjectHost"/>
     </object-type>
     <object-type name="QRemoteObjectSettingsStore"/>
     <value-type name="QRemoteObjectSourceLocationInfo"/>
+    <object-type name="QtROClientFactory"/>
+    <object-type name="QtROClientIoDevice"/>
+    <object-type name="QtROIoDeviceBase"/>
+    <object-type name="QtROServerFactory"/>
+    <object-type name="QtROServerIoDevice"/>
 
     <suppress-warning text="^.*Typedef used on signal QRemoteObject.*$"/>
     <suppress-warning text="^QRemoteObjectPendingCallWatcher inherits from a non polymorphic type.*$"/>
     <suppress-warning text="^Enum 'QRemoteObjectReplica::ConstructorType'.*does not have a type entry.*$"/>
     <suppress-warning text="Stripping argument #1 of void QRemoteObjectReplica::QRemoteObjectReplica(QRemoteObjectReplica::ConstructorType) due to unmatched type &quot;QRemoteObjectReplica::ConstructorType&quot; with default expression &quot;DefaultConstructor&quot;."/>
-    <suppress-warning text="skipping field 'QRemoteObjectReplica::d_impl' with unmatched type 'QSharedPointer'"/>
+    <suppress-warning text="skipping protected field 'QRemoteObjectReplica::d_impl' with unmatched type 'QSharedPointer'"/>
     <!-- QtNetwork is pulled in via QtRemoteObjectsDepends. -->
     <suppress-warning text="^Scoped enum 'Q(Ocsp)|(Dtls).*' does not have a type entry.*$"/>
 
index aeccf949fd5de1a0696ff8dce5057bc5a2757d52..ba882057045f66729b622ec898cc67a7b9cdef5b 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2018 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtScxml">
+<typesystem package="PySide6.QtScxml"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <object-type name="QScxmlCompiler">
         <object-type name="Loader"/>
index 924262f529b494b37d82dc84353cdbbe513a3470..4efd08277a2c1f5889288d8c1b5c632bb07ab2a6 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2018 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtSensors">
+<typesystem package="PySide6.QtSensors"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
 <!-- overrides QObject::metaObject() by private method
     <object-type name="QSensorGesture"/>
index f3bf0c805e43799f40a348c170472759be628e41..310a8b0f03a3b8030383ecf475be94e564eee2d0 100644 (file)
@@ -8,25 +8,35 @@ set(QtSerialBus_DROPPED_ENTRIES )
 
 set(QtSerialBus_SRC
     ${QtSerialBus_GEN_DIR}/qcanbus_wrapper.cpp
-    ${QtSerialBus_GEN_DIR}/qcanbusdevice_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qcanbusdevice_filter_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qcanbusdevice_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qcanbusdeviceinfo_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qcanbusfactory_wrapper.cpp
-    ${QtSerialBus_GEN_DIR}/qcanbusframe_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qcanbusframe_timestamp_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qcanbusframe_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qcandbcfileparser_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qcanframeprocessor_parseresult_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qcanframeprocessor_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qcanmessagedescription_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qcansignaldescription_multiplexvaluerange_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qcansignaldescription_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qcanuniqueiddescription_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbusclient_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbusdataunit_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbusdevice_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbusdeviceidentification_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qmodbusexceptionresponse_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbuspdu_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbusreply_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbusrequest_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qmodbusresponse_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbusrtuserialclient_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbusrtuserialserver_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbusserver_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbustcpclient_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbustcpconnectionobserver_wrapper.cpp
     ${QtSerialBus_GEN_DIR}/qmodbustcpserver_wrapper.cpp
+    ${QtSerialBus_GEN_DIR}/qtcanbus_wrapper.cpp
 # module is always needed
     ${QtSerialBus_GEN_DIR}/qtserialbus_module_wrapper.cpp
 )
index 57642f34c233e4bad1bc451223c79af410940541..fdd2b148353c5d78de4f2b52c92b5af619690558 100644 (file)
@@ -4,11 +4,19 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.QtSerialBus">
+<typesystem package="PySide6.QtSerialBus"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <load-typesystem name="QtNetwork/typesystem_network.xml" generate="no"/>
     <load-typesystem name="QtSerialPort/typesystem_serialport.xml" generate="no"/>
 
+    <namespace-type name="QtCanBus">
+        <enum-type name="DataSource"/>
+        <enum-type name="DataFormat"/>
+        <enum-type name="MultiplexState"/>
+        <enum-type name="UniqueId"/>
+    </namespace-type>
+
     <object-type name="QCanBus">
         <!-- Remove errorMessage argument, return tuple instead.  -->
         <modify-function signature="availableDevices(QString,QString*)const">
         <enum-type name="FrameError" flags="FrameErrors"/>
         <value-type name="TimeStamp"/>
     </value-type>
+    <object-type name="QCanDbcFileParser">
+        <enum-type name="Error"/>
+    </object-type>
+    <object-type name="QCanFrameProcessor">
+        <enum-type name="Error"/>
+        <value-type name="ParseResult"/>
+    </object-type>
+    <value-type name="QCanMessageDescription"/>
+    <value-type name="QCanSignalDescription">
+        <value-type name="MultiplexValueRange"/>
+    </value-type>
+    <value-type name="QCanUniqueIdDescription"/>
     <object-type name="QModbusClient"/>
     <value-type name="QModbusDataUnit">
         <enum-type name="RegisterType"/>
         <enum-type name="FunctionCode"/>
         <modify-field name="ExceptionByte" remove="true"/> <!-- Link error -->
     </object-type>
+    <object-type name="QModbusExceptionResponse"/>
+    <object-type name="QModbusResponse"/>
     <object-type name="QModbusReply">
         <enum-type name="ReplyType"/>
     </object-type>
index 929a8e909e652ac2f1e0e6166b7d949820b81cff..0cbd3c7f7c01e0723a25950bfe8e3152f9ba7534 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2020 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtSerialPort">
+<typesystem package="PySide6.QtSerialPort"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <object-type name="QSerialPort">
         <enum-type name="BaudRate" python-type="IntEnum"/>
index 409759b6fba16290cee6940ecbb9960b58b9b3d1..966c0ffe8efad6ed6d3c0d1093ec688d62b28218 100644 (file)
@@ -28,12 +28,8 @@ set(QtSpatialAudio_include_dirs ${QtSpatialAudio_SOURCE_DIR}
                                 ${QtMultimedia_GEN_DIR})
 
 set(QtSpatialAudio_libraries pyside6
-                             ${Qt${QT_MAJOR_VERSION}SpatialAudio_LIBRARIES}
-                             ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                             ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                             ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                             ${Qt${QT_MAJOR_VERSION}Multimedia_LIBRARIES}
-                             )
+                             ${Qt${QT_MAJOR_VERSION}SpatialAudio_LIBRARIES})
+
 set(QtSpatialAudio_deps QtCore QtGui QtNetwork QtMultimedia)
 
 create_pyside_module(NAME QtSpatialAudio
index 71f189b254eba919209babd5af321bdf04117f53..b9c2557afb3899d04c66079a9eac6699c1d82b82 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2022 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtSpatialAudio">
+<typesystem package="PySide6.QtSpatialAudio"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
     <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
     <load-typesystem name="QtNetwork/typesystem_network.xml" generate="no"/>
index 2150eb3c968cb8d3a746cd812f629ab60a53ca85..fedebe6429ecdd8edca96902234bc672468f931e 100644 (file)
@@ -35,13 +35,13 @@ set(QtSql_include_dirs  ${QtSql_SOURCE_DIR}
                         ${libpyside_SOURCE_DIR}
                         ${QtCore_GEN_DIR}
                         ${QtGui_GEN_DIR}
-                        ${QtWidgets_GEN_DIR}
-                        )
+                        ${QtWidgets_GEN_DIR})
+
+# Link to QtWidgets to enable QSqlRelationalDelegate
 set(QtSql_libraries     pyside6
-                        ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
                         ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
                         ${Qt${QT_MAJOR_VERSION}Sql_LIBRARIES})
+
 set(QtSql_deps QtWidgets)
 
 create_pyside_module(NAME QtSql
index 022a5ab0948c6723ef7e131414e04dd243133c37..70c3e6f695a0c5134df1bd97540d054d3ea6f335 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtSql">
+<typesystem package="PySide6.QtSql"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
 
   <rejection class="QSqlDriverCreator"/>
index 88a4805e1e11a9d81b9cfa75c9d7b0a68f82ad24..2b4cc348d03edb7ba6c74a18031b69a5ad614299 100644 (file)
@@ -26,13 +26,11 @@ set(QtStateMachine_include_dirs  ${QtStateMachine_SOURCE_DIR}
                             ${Qt${QT_MAJOR_VERSION}Gui_INCLUDE_DIRS}
                             ${libpyside_SOURCE_DIR}
                             ${QtCore_GEN_DIR}
-                            ${QtGui_GEN_DIR}
-                            )
+                            ${QtGui_GEN_DIR})
+
 set(QtStateMachine_libraries pyside6
-                        ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}StateMachine_LIBRARIES}
-                        )
+                             ${Qt${QT_MAJOR_VERSION}StateMachine_LIBRARIES})
+
 set(QtStateMachine_deps QtGui)
 
 create_pyside_module(NAME QtStateMachine
index bad0cc8edde0c1f418ea5888523ea2ae12e38acb..0e29f240f65d55a8f01cd91f4325f0eeb1c0fcac 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2021 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtStateMachine">
+<typesystem package="PySide6.QtStateMachine"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
 
   <object-type name="QAbstractState">
index 60be42cbfc739cdc23945904876a3f7d090a7d12..5451380cc2cbde1b04ebf2a51fcaca732eb68913 100644 (file)
@@ -6,6 +6,7 @@ project(QtSvg)
 set(QtSvg_SRC
 ${QtSvg_GEN_DIR}/qsvggenerator_wrapper.cpp
 ${QtSvg_GEN_DIR}/qsvgrenderer_wrapper.cpp
+${QtSvg_GEN_DIR}/qtsvg_wrapper.cpp
 # module is always needed
 ${QtSvg_GEN_DIR}/qtsvg_module_wrapper.cpp
 )
@@ -17,13 +18,12 @@ set(QtSvg_include_dirs  ${QtSvg_SOURCE_DIR}
                         ${Qt${QT_MAJOR_VERSION}Svg_INCLUDE_DIRS}
                         ${libpyside_SOURCE_DIR}
                         ${QtCore_GEN_DIR}
-                        ${QtGui_GEN_DIR}
-                        )
+                        ${QtGui_GEN_DIR})
+
 set(QtSvg_libraries     pyside6
-                        ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}Svg_LIBRARIES}
-                        )
+                        ${Qt${QT_MAJOR_VERSION}Svg_LIBRARIES})
+
+
 set(QtSvg_deps QtGui)
 
 create_pyside_module(NAME QtSvg
index 834d8101b28872aa3f56e5720713bb4fb4b17d65..4803f4d93fb271c83dc3357863bcaac405b623f7 100644 (file)
@@ -3,10 +3,14 @@
 // Copyright (C) 2020 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtSvg">
+<typesystem package="PySide6.QtSvg"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
 
   <object-type name="QSvgRenderer"/>
+  <namespace-type name="QtSvg" since="6.7">
+      <enum-type name="Option" flags="Options"/>
+  </namespace-type>
 
   <object-type name="QSvgGenerator">
     <enum-type name="SvgVersion" since="6.5"/>
index 9203ac0033e974f41d96d3f5274526cddf2f7261..6bd3aedc1b611e433b0ce95dd2936d4c0ac57536 100644 (file)
@@ -21,16 +21,10 @@ set(QtSvgWidgets_include_dirs ${QtSvgWidgets_SOURCE_DIR}
                               ${QtCore_GEN_DIR}
                               ${QtGui_GEN_DIR}
                               ${QtWidgets_GEN_DIR}
-                              ${QtSvg_GEN_DIR}
-                              )
+                              ${QtSvg_GEN_DIR})
 
 set(QtSvgWidgets_libraries pyside6
-                           ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                           ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                           ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
-                           ${Qt${QT_MAJOR_VERSION}Svg_LIBRARIES}
-                           ${Qt${QT_MAJOR_VERSION}SvgWidgets_LIBRARIES}
-                           )
+                           ${Qt${QT_MAJOR_VERSION}SvgWidgets_LIBRARIES})
 
 set(QtSvgWidgets_deps QtSvg QtWidgets)
 
index ce7a02c6851ebe297167719f375e3907d96e9642..36bda1ea3ba601f21c08cf2911c675277b9f9f79 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2020 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtSvgWidgets">
+<typesystem package="PySide6.QtSvgWidgets"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtSvg/typesystem_svg.xml" generate="no"/>
   <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
 
index e04903df99be6b1fa12f5a23953c9d03a9e293d7..86bb2a7316dde1a43d7833e30f4d7522b543917e 100644 (file)
@@ -27,14 +27,15 @@ set(QtTest_include_dirs ${QtTest_SOURCE_DIR}
                         ${libpyside_SOURCE_DIR}
                         ${QtCore_GEN_DIR}
                         ${QtGui_GEN_DIR}
-                        ${QtWidgets_GEN_DIR}
-                        )
+                        ${QtWidgets_GEN_DIR})
+
+# Link to QtGui/QtWidgets to enable gui/widget-specific inline functions
 set(QtTest_libraries    pyside6
                         ${Qt${QT_MAJOR_VERSION}Test_LIBRARIES}
                         ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
                         ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                        )
+                        ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES})
+
 set(QtTest_deps  QtWidgets)
 
 create_pyside_module(NAME QtTest
index 084b18a174e42e74936af5661f093d4e5ac2ccde..2fc4f23cd0c5862a21f666b6f70ab3f3c4993044 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtTest">
+<typesystem package="PySide6.QtTest"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
   <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
   <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
index 7f8db54b0aaf49085550dea207e16adbf2b2400f..9f0bd2fc307b9450bebd65c2347442b60f57c7ff 100644 (file)
@@ -19,9 +19,7 @@ set(QtTextToSpeech_include_dirs ${QtTextToSpeech_SOURCE_DIR}
                                 ${QtCore_GEN_DIR})
 
 set(QtTextToSpeech_libraries    pyside6
-                                ${Qt${QT_MAJOR_VERSION}Multimedia_LIBRARIES}
-                                ${Qt${QT_MAJOR_VERSION}TextToSpeech_LIBRARIES}
-                                ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES})
+                                ${Qt${QT_MAJOR_VERSION}TextToSpeech_LIBRARIES})
 
 set(QtTextToSpeech_deps QtCore QtMultimedia)
 
index 985c4994cf533cf89240c059d2454646bd7f59c0..70751e9d946e53b2205e0891c7c5ee3609cb1474 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2017 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtTextToSpeech">
+<typesystem package="PySide6.QtTextToSpeech"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
 
   <object-type name="QTextToSpeech">
index b7385b873b473031904f11f6262fcded102a95bc..e16d2d585924ff8c730e628dbbeb2a4d1ac7fbc8 100644 (file)
@@ -25,15 +25,12 @@ set(QtUiTools_include_dirs  ${QtUiTools_SOURCE_DIR}
                             ${plugins_SOURCE_DIR}
                             ${QtCore_GEN_DIR}
                             ${QtGui_GEN_DIR}
-                            ${QtWidgets_GEN_DIR}
-                            )
+                            ${QtWidgets_GEN_DIR})
+
 set(QtUiTools_libraries     pyside6
                             uiplugin
-                            ${Qt${QT_MAJOR_VERSION}UiTools_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
-                            )
+                            ${Qt${QT_MAJOR_VERSION}UiTools_LIBRARIES})
+
 set(QtUiTools_deps QtWidgets)
 
 configure_file("${QtUiTools_SOURCE_DIR}/QtUiTools_global.pre.h.in"
index a67dd6f61bf4e8c532e938f3c9cecb4a65265c10..9cfa176c842a6267bcb988205d291003fa273660 100644 (file)
@@ -4,7 +4,8 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
 
-<typesystem package="PySide6.QtUiTools">
+<typesystem package="PySide6.QtUiTools"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
 
     <object-type name="QUiLoader">
       <inject-code class="native" position="beginning" file="../glue/qtuitools.cpp" snippet="uitools-loadui"/>
       <inject-code file="../glue/qtuitools.cpp" snippet="quiloader"/>
       <add-function signature="registerCustomWidget(PyObject*@customWidgetType@)" return-type="void">
-         <inject-documentation format="target" mode="append">
-         Registers a Python created custom widget to QUiLoader, so it can be recognized when
-         loading a `.ui` file. The custom widget type is passed via the ``customWidgetType`` argument.
-         This is needed when you want to override a virtual method of some widget in the interface,
-         since duck punching will not work with widgets created by QUiLoader based on the contents
-         of the `.ui` file.
-
-         (Remember that `duck punching virtual methods is an invitation for your own demise!
-         &lt;https://doc.qt.io/qtforpython/shiboken6/wordsofadvice.html#duck-punching-and-virtual-methods>`_)
-
-         Let's see an obvious example. If you want to create a new widget it's probable you'll end up
-         overriding :class:`~PySide6.QtGui.QWidget`'s :meth:`~PySide6.QtGui.QWidget.paintEvent` method.
-
-         .. code-block:: python
-
-            class Circle(QWidget):
-                def paintEvent(self, event):
-                    with QPainter(self) as painter:
-                        painter.setPen(self.pen)
-                        painter.setBrush(QBrush(self.color))
-                        painter.drawEllipse(event.rect().center(), 20, 20)
-
-            # ...
-
-            loader = QUiLoader()
-            loader.registerCustomWidget(Circle)
-            circle = loader.load('circle.ui')
-            circle.show()
-
-            # ...
-         </inject-documentation>
-         <inject-code class="target" position="beginning" file="../glue/qtuitools.cpp" snippet="quiloader-registercustomwidget"/>
+         <inject-documentation format="target" mode="append" file="../doc/qtuitools.rst"
+                               snippet="quiloader-registercustomwidget"/>
+         <inject-code class="target" position="beginning" file="../glue/qtuitools.cpp"
+                      snippet="quiloader-registercustomwidget"/>
       </add-function>
       <modify-function signature="createAction(QObject*,const QString&amp;)">
         <modify-argument index="return">
     -->
     <add-function signature="loadUiType(const QString&amp; @uifile@)" return-type="PyObject*">
       <inject-code file="../glue/qtuitools.cpp" snippet="loaduitype"/>
+      <inject-documentation format="target" mode="append" file="../doc/qtuitools.rst"
+                            snippet="loaduitype"/>
     </add-function>
 
 
index ecb2caf52d32fc7cae6f2d9038aa8aae473baea3..4c06edd2f0fa25c5fe42ccc69731013bd30b864a 100644 (file)
@@ -15,12 +15,11 @@ set(QtWebChannel_include_dirs ${QtWebChannel_SOURCE_DIR}
                         ${Qt${QT_MAJOR_VERSION}Core_INCLUDE_DIRS}
                         ${Qt${QT_MAJOR_VERSION}WebChannel_INCLUDE_DIRS}
                         ${libpyside_SOURCE_DIR}
-                        ${QtCore_GEN_DIR}
-                        )
-set(QtWebChannel_libraries    pyside6
-                        ${Qt${QT_MAJOR_VERSION}WebChannel_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                        )
+                        ${QtCore_GEN_DIR})
+
+set(QtWebChannel_libraries pyside6
+                           ${Qt${QT_MAJOR_VERSION}WebChannel_LIBRARIES})
+
 set(QtWebChannel_deps QtCore)
 
 create_pyside_module(NAME QtWebChannel
index 75a51853f83aaed628198be607ec69654d379834..c08a9b1876f0686d09483248b1719c2ab6dd5def 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtWebChannel">
+<typesystem package="PySide6.QtWebChannel"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
 
   <object-type name="QWebChannel"/>
index 3f376fd48cf5eb1b2b0d67aa4385f9781484cf63..0cdaf2f911446163dcac294d62b97f7369b575e4 100644 (file)
@@ -5,17 +5,25 @@ project(QtWebEngineCore)
 
 set(QtWebEngineCore_SRC
 ${QtWebEngineCore_GEN_DIR}/qwebenginecertificateerror_wrapper.cpp
+${QtWebEngineCore_GEN_DIR}/qwebengineclientcertificateselection_wrapper.cpp
+${QtWebEngineCore_GEN_DIR}/qwebengineclientcertificatestore_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginecontextmenurequest_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginecookiestore_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginecookiestore_filterrequest_wrapper.cpp
+# FIXME ${QtWebEngineCore_GEN_DIR}/qwebenginedesktopmediarequest_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginedownloadrequest_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginefilesystemaccessrequest_wrapper.cpp
+${QtWebEngineCore_GEN_DIR}/qwebenginefindtextresult_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginefullscreenrequest_wrapper.cpp
+${QtWebEngineCore_GEN_DIR}/qwebengineglobalsettings_wrapper.cpp
+${QtWebEngineCore_GEN_DIR}/qwebengineglobalsettings_dnsmode_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginehistory_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginehistoryitem_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginehistorymodel_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginehttprequest_wrapper.cpp
+${QtWebEngineCore_GEN_DIR}/qwebenginenavigationrequest_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebengineloadinginfo_wrapper.cpp
+# FIXME ${QtWebEngineCore_GEN_DIR}/qwebenginemediasourcemodel_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginenewwindowrequest_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginenotification_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginepage_wrapper.cpp
@@ -25,12 +33,13 @@ ${QtWebEngineCore_GEN_DIR}/qwebengineregisterprotocolhandlerrequest_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginescript_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginescriptcollection_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebenginesettings_wrapper.cpp
-${QtWebEngineCore_GEN_DIR}/qwebenginefindtextresult_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebengineurlrequestinfo_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebengineurlrequestinterceptor_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebengineurlrequestjob_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebengineurlscheme_wrapper.cpp
 ${QtWebEngineCore_GEN_DIR}/qwebengineurlschemehandler_wrapper.cpp
+${QtWebEngineCore_GEN_DIR}/qwebenginewebauthpinrequest_wrapper.cpp
+${QtWebEngineCore_GEN_DIR}/qwebenginewebauthuxrequest_wrapper.cpp
 # module is always needed
 ${QtWebEngineCore_GEN_DIR}/qtwebenginecore_module_wrapper.cpp
 )
@@ -50,17 +59,10 @@ set(QtWebEngineCore_include_dirs
                             ${QtWidgets_GEN_DIR}
                             ${QtNetwork_GEN_DIR}
                             ${QtPrintSupport_GEN_DIR}
-                            ${QtWebChannel_GEN_DIR}
-                            )
+                            ${QtWebChannel_GEN_DIR})
+
 set(QtWebEngineCore_libraries pyside6
-                            ${Qt${QT_MAJOR_VERSION}WebEngineCore_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}PrintSupport_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}WebChannel_LIBRARIES}
-                            )
+                              ${Qt${QT_MAJOR_VERSION}WebEngineCore_LIBRARIES})
 
 set(QtWebEngineCore_deps QtCore QtGui QtNetwork QtPrintSupport QtWebChannel)
 
index ff88b3584a0ec0cf232ce93e11fb5256bd20761b..da9259ccc14488f5d1f0cde3490eb901235ca7e6 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2018 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtWebEngineCore">
+<typesystem package="PySide6.QtWebEngineCore"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
   <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
   <load-typesystem name="QtNetwork/typesystem_network.xml" generate="no"/>
   <function signature="qWebEngineChromiumSecurityPatchVersion()"/>
   <function signature="qWebEngineVersion()"/>
 
+  <value-type name="QWebEngineClientCertificateSelection"/>
+  <object-type name="QWebEngineClientCertificateStore"/>
+
   <object-type name="QWebEngineCookieStore">
+    <inject-code class="native" position="beginning" file="../glue/qtwebenginecore.cpp"
+                 snippet="qwebenginecookiestore-functor"/>
     <value-type name="FilterRequest" />
     <add-function signature="setCookieFilter(PyCallable* @filterCallback@)">
       <inject-code class="target" position="beginning" file="../glue/qtwebenginecore.cpp"
     <enum-type name="Roles"/>
   </object-type>
 
+  <object-type name="QWebEngineNavigationRequest">
+      <enum-type name="NavigationType"/>
+      <enum-type name="NavigationRequestAction"/>
+  </object-type>
+
   <object-type name="QWebEngineNotification"/>
 
   <object-type name="QWebEnginePage">
     <enum-type name="FileSelectionMode"/>
     <enum-type name="JavaScriptConsoleMessageLevel"/>
     <enum-type name="RenderProcessTerminationStatus"/>
+    <add-function signature="javaScriptPromptPyOverride(QUrl@securityOrigin@,QString@msg@,QString@defaultValue@)"
+                  return-type="std::pair&lt;bool,QString&gt;" python-override="true"/>
+    <modify-function signature="javaScriptPrompt(QUrl,QString,QString,QString*)">
+      <inject-code class="shell" position="override" file="../glue/qtwebenginecore.cpp"
+                   snippet="qwebenginepage-javascriptprompt-virtual-redirect"/>
+      <modify-argument index="return" pyi-type="Tuple[bool, str]"/>
+      <modify-argument index="4"><remove-default-expression/><remove-argument/></modify-argument>
+      <inject-code class="target" position="beginning" file="../glue/qtwebenginecore.cpp"
+                   snippet="qwebenginepage-javascriptprompt-return"/>
+    </modify-function>
     <add-function signature="findText(const QString &amp;,QWebEnginePage::FindFlags,PyObject*)">
         <inject-code class="target" position="beginning" file="../glue/qtwebenginewidgets.cpp" snippet="qwebenginepage-findtext"/>
     </add-function>
     <extra-includes>
         <include file-name="QtWebEngineCore/QWebEngineNotification" location="global"/>
     </extra-includes>
+    <inject-code class="native" position="beginning" file="../glue/qtwebenginecore.cpp"
+                 snippet="qwebengineprofile-functor"/>
     <enum-type name="HttpCacheType"/>
     <enum-type name="PersistentCookiesPolicy"/>
     <add-function signature="setNotificationPresenter(PyCallable* @notificationPresenter@)">
     <enum-type name="LoadStatus"/>
   </value-type>
 
-  <object-type name="QWebEngineRegisterProtocolHandlerRequest"/>
+  <value-type name="QWebEngineRegisterProtocolHandlerRequest"/>
 
   <value-type name="QWebEngineFindTextResult"/>
 
 
   <object-type name="QWebEngineUrlSchemeHandler"/>
 
+  <!-- FIXME  not in snapshot yet
+  <value-type name="QWebEngineDesktopMediaRequest" since="6.7"/>
+  <object-type name="QWebEngineMediaSourceModel" since="6.7"/>
+  -->
+  <value-type name="QWebEngineWebAuthPinRequest" since="6.7"/>
+  <object-type name="QWebEngineWebAuthUxRequest" since="6.7">
+      <enum-type name="WebAuthUxState"/>
+      <enum-type name="PinEntryReason"/>
+      <enum-type name="PinEntryError"/>
+      <enum-type name="RequestFailureReason"/>
+  </object-type>
+  <namespace-type name="QWebEngineGlobalSettings">
+      <enum-type name="SecureDnsMode"/>
+      <value-type name="DnsMode"/>
+  </namespace-type>
+
   <!-- QtQml is pulled in via QtWebEngineCoreDepends. -->
   <suppress-warning text="^Scoped enum 'QQml.*' does not have a type entry.*$"/>
 
index 63bc14f40f53f5c9de546f7d11d3950450cd66a3..d87dc55a45d9d51635997fc9276a3db092f83f12 100644 (file)
@@ -14,22 +14,26 @@ set(QtWebEngineQuick_include_dirs
                             ${QtWebEngineQuick_SOURCE_DIR}
                             ${QtWebEngineQuick_BINARY_DIR}
                             ${Qt${QT_MAJOR_VERSION}Core_INCLUDE_DIRS}
+                            ${Qt${QT_MAJOR_VERSION}Gui_INCLUDE_DIRS}
+                            ${Qt${QT_MAJOR_VERSION}Widgets_INCLUDE_DIRS}
                             ${Qt${QT_MAJOR_VERSION}Network_INCLUDE_DIRS}
+                            ${Qt${QT_MAJOR_VERSION}PrintSupport_INCLUDE_DIRS}
                             ${Qt${QT_MAJOR_VERSION}Qml_INCLUDE_DIRS}
+                            ${Qt${QT_MAJOR_VERSION}WebChannel_INCLUDE_DIRS}
                             ${libpyside_SOURCE_DIR}
                             ${QtCore_GEN_DIR}
+                            ${QtGui_GEN_DIR}
+                            ${QtWidgets_GEN_DIR}
                             ${QtNetwork_GEN_DIR}
+                            ${QtWebEngineCore_GEN_DIR}
+                            ${QtPrintSupport_GEN_DIR}
                             ${QtQml_GEN_DIR}
-                            )
+                            ${QtWebChannel_GEN_DIR})
 
 set(QtWebEngineQuick_libraries pyside6
-                            ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Qml_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}WebEngineQuick_LIBRARIES}
-                            )
+                               ${Qt${QT_MAJOR_VERSION}WebEngineQuick_LIBRARIES})
 
-set(QtWebEngineQuick_deps QtQml QtNetwork QtCore)
+set(QtWebEngineQuick_deps QtQml QtWebEngineCore)
 
 create_pyside_module(NAME QtWebEngineQuick
                      INCLUDE_DIRS QtWebEngineQuick_include_dirs
index 72a31deb2e9690953aee11682adb49c609862c58..2e7d223349db4c27769777393ae23199516fb9e6 100644 (file)
@@ -3,8 +3,10 @@
 // Copyright (C) 2021 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtWebEngineQuick">
+<typesystem package="PySide6.QtWebEngineQuick"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtQml/typesystem_qml.xml" generate="no"/>
+    <load-typesystem name="QtWebEngineCore/typesystem_webenginecore.xml" generate="no"/>
 
     <namespace-type name="QtWebEngineQuick"/> <!-- initialize() -->
 
index de8c41f5f64e4a6c28170818003e367541d4171e..9da97243c8fa5723757b4e5a573452f4430417de 100644 (file)
@@ -27,17 +27,10 @@ set(QtWebEngineWidgets_include_dirs
                             ${QtNetwork_GEN_DIR}
                             ${QtWebEngineCore_GEN_DIR}
                             ${QtPrintSupport_GEN_DIR}
-                            ${QtWebChannel_GEN_DIR}
-                            )
-set(QtWebEngineWidgets_libraries      pyside6
-                            ${Qt${QT_MAJOR_VERSION}WebEngineWidgets_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}PrintSupport_LIBRARIES}
-                            ${Qt${QT_MAJOR_VERSION}WebChannel_LIBRARIES}
-                            )
+                            ${QtWebChannel_GEN_DIR})
+
+set(QtWebEngineWidgets_libraries pyside6
+                                 ${Qt${QT_MAJOR_VERSION}WebEngineWidgets_LIBRARIES})
 
 set(QtWebEngineWidgets_deps QtGui QtWidgets QtNetwork QtPrintSupport QtWebChannel QtWebEngineCore)
 
index fb5e6d3798d17e4a81d8f64f3ac5c27c3bebf705..61874856b534401b44c1839600e8e260936f93ff 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtWebEngineWidgets">
+<typesystem package="PySide6.QtWebEngineWidgets"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
   <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
   <load-typesystem name="QtWidgets/typesystem_widgets.xml" generate="no"/>
index b51b5d10e89ea2bd5bd3a87e3d33032b6e78a828..5ff07555bb8b33d67ffb5b50f69f63aea74dc3b1 100644 (file)
@@ -22,13 +22,10 @@ set(QtWebSockets_include_dirs ${QtWebSockets_SOURCE_DIR}
                         ${libpyside_SOURCE_DIR}
                         ${QtCore_GEN_DIR}
                         ${QtWebSockets_GEN_DIR}
-                        ${QtNetwork_GEN_DIR}
-                        )
-set(QtWebSockets_libraries    pyside6
-                        ${Qt${QT_MAJOR_VERSION}WebSockets_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}Network_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                        )
+                        ${QtNetwork_GEN_DIR})
+
+set(QtWebSockets_libraries pyside6
+                           ${Qt${QT_MAJOR_VERSION}WebSockets_LIBRARIES})
 
 set(QtWebSockets_deps QtNetwork)
 
index 914c8ce81d987a905b0956fa9daa9445cc34174c..2d8d95898f15f90dd395d7c04338311162f35c9e 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtWebSockets">
+<typesystem package="PySide6.QtWebSockets"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="QtCore/typesystem_core.xml" generate="no"/>
   <load-typesystem name="QtNetwork/typesystem_network.xml" generate="no"/>
 
index 3ce30d469f17af16059d1794fbf04d42e664218f..1a77181f2f1c27fa9a38d6606dd6490de2329d4c 100644 (file)
@@ -116,6 +116,7 @@ ${QtWidgets_GEN_DIR}/qprogressdialog_wrapper.cpp
 ${QtWidgets_GEN_DIR}/qproxystyle_wrapper.cpp
 ${QtWidgets_GEN_DIR}/qpushbutton_wrapper.cpp
 ${QtWidgets_GEN_DIR}/qradiobutton_wrapper.cpp
+${QtWidgets_GEN_DIR}/qrhiwidget_wrapper.cpp
 ${QtWidgets_GEN_DIR}/qrubberband_wrapper.cpp
 ${QtWidgets_GEN_DIR}/qscrollarea_wrapper.cpp
 ${QtWidgets_GEN_DIR}/qscrollbar_wrapper.cpp
@@ -209,13 +210,11 @@ set(QtWidgets_include_dirs  ${QtWidgets_SOURCE_DIR}
                             ${Qt${QT_MAJOR_VERSION}Widgets_INCLUDE_DIRS}
                             ${libpyside_SOURCE_DIR}
                             ${QtCore_GEN_DIR}
-                            ${QtGui_GEN_DIR}
-                            )
+                            ${QtGui_GEN_DIR})
+
 set(QtWidgets_libraries pyside6
-                        ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}Gui_LIBRARIES}
-                        ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES}
-                        )
+                        ${Qt${QT_MAJOR_VERSION}Widgets_LIBRARIES})
+
 set(QtWidgets_deps QtGui)
 
 create_pyside_module(NAME QtWidgets
index fabd87d22028caa9517f0da4cc3273e72d8222d2..93a7151fca74a31a4a6eca23090bcfe7eb113eb2 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtWidgets">
+<typesystem package="PySide6.QtWidgets"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtGui/typesystem_gui.xml" generate="no"/>
     <load-typesystem name="QtWidgets/typesystem_widgets_common.xml" generate="yes"/>
 </typesystem>
index 956dedbb0aed163fa015ed767b81690f2fc92f17..0669c18f65022a63335dcab2e0218be50c467cdd 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtWidgets">
+<typesystem package="PySide6.QtWidgets"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
   <load-typesystem name="templates/core_common.xml" generate="no"/>
   <load-typesystem name="templates/widgets_common.xml" generate="no"/>
 
   <function signature="qDrawWinPanel(QPainter*,const QRect&amp;,const QPalette&amp;,bool,const QBrush*)"/>
   <function signature="qDrawPlainRect(QPainter*,int,int,int,int,const QColor&amp;,int,const QBrush*)"/>
   <function signature="qDrawPlainRect(QPainter*,const QRect&amp;,const QColor&amp;,int,const QBrush*)"/>
+  <function signature="qDrawPlainRoundedRect(QPainter*,int,int,int,int,qreal,qreal,const QColor&amp;,int,const QBrush*)" since="6.7"/>
+  <function signature="qDrawPlainRoundedRect(QPainter*,const QRect&amp;,qreal,qreal,const QColor&amp;,int,const QBrush *)" since="6.7"/>
 
-  <object-type name="QStyleOption" polymorphic-id-expression="%1-&gt;type == QStyleOption::SO_Default"
+  <object-type name="QStyleOption" polymorphic-id-expression="%B-&gt;type == QStyleOption::SO_Default"
                polymorphic-name-function="styleOptionType">
     <inject-code class="native" position="beginning" file="../glue/qtwidgets.cpp"
                  snippet="qstyleoption-typename"/>
     <enum-type name="StyleOptionType"/>
     <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionGraphicsItem" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionGraphicsItem *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionGraphicsItem"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionGraphicsItem *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionSizeGrip" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionSizeGrip *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionSizeGrip"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionSizeGrip *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionButton" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionButton *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionButton"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionButton *&gt;(%B) != nullptr">
       <enum-type name="ButtonFeature" flags="ButtonFeatures"/>
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionComboBox" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionComboBox *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionComboBox"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionComboBox *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionComplex" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionComplex *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionComplex"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionComplex *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionDockWidget" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionDockWidget *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionDockWidget"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionDockWidget *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionFocusRect" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionFocusRect *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionFocusRect" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionFocusRect *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionFrame" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionFrame *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionFrame"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionFrame *&gt;(%B) != nullptr">
       <enum-type name="FrameFeature" flags="FrameFeatures"/>
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionGroupBox" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionGroupBox *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionGroupBox"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionGroupBox *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionHeader" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionHeader *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionHeader"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionHeader *&gt;(%B) != nullptr">
       <enum-type name="SectionPosition"/>
       <enum-type name="SelectedPosition"/>
       <enum-type name="SortIndicator"/>
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionMenuItem" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionMenuItem *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionMenuItem"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionMenuItem *&gt;(%B) != nullptr">
       <enum-type name="CheckType"/>
       <enum-type name="MenuItemType"/>
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionProgressBar" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionProgressBar *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionProgressBar"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionProgressBar *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionRubberBand" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionRubberBand *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionRubberBand"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionRubberBand *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionSlider" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionSlider *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionSlider"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionSlider *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionSpinBox" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionSpinBox *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionSpinBox"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionSpinBox *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionTab" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionTab *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionTab"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionTab *&gt;(%B) != nullptr">
       <enum-type name="CornerWidget" flags="CornerWidgets"/>
       <enum-type name="SelectedPosition"/>
       <enum-type name="StyleOptionType"/>
       <enum-type name="TabFeature" flags="TabFeatures"/>
       <enum-type name="TabPosition"/>
   </object-type>
-  <object-type name="QStyleOptionTabBarBase" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionTabBarBase *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionTabBarBase"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionTabBarBase *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionTabWidgetFrame" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionTabWidgetFrame *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionTabWidgetFrame"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionTabWidgetFrame *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionTitleBar" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionTitleBar *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionTitleBar" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionTitleBar *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   </object-type>
-  <object-type name="QStyleOptionToolBar" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionToolBar *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionToolBar"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionToolBar *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
       <enum-type name="ToolBarFeature" flags="ToolBarFeatures"/>
       <enum-type name="ToolBarPosition"/>
   </object-type>
-  <object-type name="QStyleOptionToolBox" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionToolBox *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionToolBox"
+               polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionToolBox *&gt;(%B) != nullptr">
       <enum-type name="SelectedPosition"/>
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
       <enum-type name="TabPosition"/>
   </object-type>
-  <object-type name="QStyleOptionToolButton" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionToolButton *&gt;(%1) != nullptr">
+  <object-type name="QStyleOptionToolButton" polymorphic-id-expression="qstyleoption_cast&lt;const QStyleOptionToolButton *&gt;(%B) != nullptr">
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
       <enum-type name="ToolButtonFeature" flags="ToolButtonFeatures"/>
   </object-type>
-  <value-type name="QStyleOptionViewItem" polymorphic-id-expression="%1-&gt;type == QStyleOptionViewItem::Type &amp;&amp; %1-&gt;version == QStyleOptionViewItem::Version">
+  <value-type name="QStyleOptionViewItem"
+              polymorphic-id-expression="%B-&gt;type == QStyleOptionViewItem::Type &amp;&amp; %B-&gt;version == QStyleOptionViewItem::Version">
       <enum-type name="Position"/>
       <enum-type name="StyleOptionType"/>
       <enum-type name="StyleOptionVersion"/>
   <object-type name="QDateEdit"/>
   <object-type name="QDialog">
     <enum-type name="DialogCode" python-type="IntEnum"/>
-    <modify-function signature="exec()" allow-thread="yes"/>
+    <modify-function signature="exec()" allow-thread="yes">
+        <inject-code file="../glue/qtwidgets.cpp" snippet="qdialog-exec-remove-parent-relation"/>
+    </modify-function>
     <add-function signature="exec_()" return-type="int">
         <inject-code file="../glue/qtwidgets.cpp" snippet="qapplication-exec"/>
     </add-function>
       </modify-argument>
     </modify-function>
   </object-type>
-  <object-type name="QWidgetItem" polymorphic-id-expression="%1-&gt;widget()"/>
+  <object-type name="QWidgetItem" polymorphic-id-expression="%B-&gt;widget()"/>
 
-  <object-type name="QGraphicsSceneContextMenuEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::GraphicsSceneContextMenu">
+  <object-type name="QGraphicsSceneContextMenuEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::GraphicsSceneContextMenu">
       <enum-type name="Reason"/>
   </object-type>
-  <object-type name="QGraphicsSceneDragDropEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::GraphicsSceneDragEnter || %1-&gt;type() == QEvent::GraphicsSceneDragLeave || %1-&gt;type() == QEvent::GraphicsSceneDragMove || %1-&gt;type() == QEvent::GraphicsSceneDrop" >
+  <object-type name="QGraphicsSceneDragDropEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::GraphicsSceneDragEnter || %B-&gt;type() == QEvent::GraphicsSceneDragLeave || %B-&gt;type() == QEvent::GraphicsSceneDragMove || %B-&gt;type() == QEvent::GraphicsSceneDrop" >
     <!-- ### "setMimeData(const QMimeData*)" is an internal method. -->
     <modify-function signature="setMimeData(const QMimeData*)" remove="all"/>
     <!-- ### "setSource(QWidget*)" is an internal method. -->
     <!-- ### "setWidget(QWidget*)" is an internal method. -->
     <modify-function signature="setWidget(QWidget*)" remove="all"/>
   </object-type>
-  <object-type name="QGraphicsSceneMoveEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::GraphicsSceneMove"/>
-  <object-type name="QGraphicsSceneResizeEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::GraphicsSceneResize"/>
-  <object-type name="QGraphicsSceneHelpEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::GraphicsSceneHelp"/>
-  <object-type name="QGraphicsSceneHoverEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::GraphicsSceneHoverEnter || %1-&gt;type() == QEvent::GraphicsSceneHoverLeave || %1-&gt;type() == QEvent::GraphicsSceneHoverMove"/>
-  <object-type name="QGraphicsSceneMouseEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::GraphicsSceneMouseDoubleClick || %1-&gt;type() == QEvent::GraphicsSceneMouseMove || %1-&gt;type() == QEvent::GraphicsSceneMousePress || %1-&gt;type() == QEvent::GraphicsSceneMouseRelease"/>
-  <object-type name="QGraphicsSceneWheelEvent" copyable="false" polymorphic-id-expression="%1-&gt;type() == QEvent::GraphicsSceneWheel"/>
-
-  <object-type name="QGestureEvent" polymorphic-id-expression="%1-&gt;type() == QEvent::Gesture || %1-&gt;type() == QEvent::GestureOverride" since="4.6">
+  <object-type name="QGraphicsSceneMoveEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::GraphicsSceneMove"/>
+  <object-type name="QGraphicsSceneResizeEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::GraphicsSceneResize"/>
+  <object-type name="QGraphicsSceneHelpEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::GraphicsSceneHelp"/>
+  <object-type name="QGraphicsSceneHoverEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::GraphicsSceneHoverEnter || %B-&gt;type() == QEvent::GraphicsSceneHoverLeave || %B-&gt;type() == QEvent::GraphicsSceneHoverMove"/>
+  <object-type name="QGraphicsSceneMouseEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::GraphicsSceneMouseDoubleClick || %B-&gt;type() == QEvent::GraphicsSceneMouseMove || %B-&gt;type() == QEvent::GraphicsSceneMousePress || %B-&gt;type() == QEvent::GraphicsSceneMouseRelease"/>
+  <object-type name="QGraphicsSceneWheelEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::GraphicsSceneWheel"/>
+
+  <object-type name="QGestureEvent"
+               polymorphic-id-expression="%B-&gt;type() == QEvent::Gesture || %B-&gt;type() == QEvent::GestureOverride" since="4.6">
     <modify-function signature="activeGestures()const">
       <modify-argument index="return">
         <define-ownership owner="default"/>
       <modify-argument index="return">
         <define-ownership owner="default"/>
       </modify-argument>
-      <inject-code class="target" position="end" file="../glue/qtwidgets.cpp" snippet="addownership-0"/>
+      <inject-code class="target" position="end" file="../glue/qtwidgets.cpp"
+                   snippet="addownership-item-at"/>
     </modify-function>
 
     <modify-function signature="removeWidget(QWidget*)">
       <modify-argument index="return">
         <define-ownership owner="default"/>
       </modify-argument>
-      <inject-code class="target" position="end" file="../glue/qtwidgets.cpp" snippet="addownership-0"/>
+      <inject-code class="target" position="end" file="../glue/qtwidgets.cpp"
+                   snippet="addownership-item-at"/>
     </modify-function>
     <modify-function signature="addWidget(QWidget*,int,int,QFlags&lt;Qt::AlignmentFlag&gt;)">
       <modify-argument index="4">
 
   <object-type name="QCommandLinkButton"/>
   <!-- FIXME PYSIDE7: Move to QtGui -->
-  <object-type name="QFileSystemModel" polymorphic-id-expression="qobject_cast&lt;QFileSystemModel*&gt;(%1)">
+  <object-type name="QFileSystemModel" polymorphic-id-expression="qobject_cast&lt;QFileSystemModel*&gt;(%B)">
     <enum-type name="Roles" python-type="IntEnum"/>
     <enum-type name="Option" flags="Options"/>
     <modify-function signature="setIconProvider(QAbstractFileIconProvider*)">
   <object-type name="QPinchGesture" since="4.6">
       <enum-type name="ChangeFlag" flags="ChangeFlags"/>
   </object-type>
+
+  <object-type name="QRhiWidget" since="6.7">
+      <enum-type name="Api"/>
+      <enum-type name="TextureFormat"/>
+  </object-type>
+
   <object-type name="QSwipeGesture" since="4.6">
       <enum-type name="SwipeDirection"/>
   </object-type>
index 82001cc60a88361c1beb3a54840e92261f378680..b0e4630dd7337198bd419055c57fe6892d21572d 100644 (file)
@@ -9,6 +9,7 @@ ${QtXml_GEN_DIR}/qdomcdatasection_wrapper.cpp
 ${QtXml_GEN_DIR}/qdomcharacterdata_wrapper.cpp
 ${QtXml_GEN_DIR}/qdomcomment_wrapper.cpp
 ${QtXml_GEN_DIR}/qdomdocument_wrapper.cpp
+${QtXml_GEN_DIR}/qdomdocument_parseresult_wrapper.cpp
 ${QtXml_GEN_DIR}/qdomdocumentfragment_wrapper.cpp
 ${QtXml_GEN_DIR}/qdomdocumenttype_wrapper.cpp
 ${QtXml_GEN_DIR}/qdomelement_wrapper.cpp
index 6b850f2cbf29fc55ae7f0d81790c1f562af3db92..3661a67bfb0d984f3c471a67669fb0ffd01792fe 100644 (file)
@@ -3,7 +3,8 @@
 // Copyright (C) 2016 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 -->
-<typesystem package="PySide6.QtXml">
+<typesystem package="PySide6.QtXml"
+            namespace-begin="QT_BEGIN_NAMESPACE" namespace-end="QT_END_NAMESPACE">
     <load-typesystem name="QtCore/typesystem_core.xml" generate="no" />
     <load-typesystem name="templates/core_common.xml" generate="no" />
 
@@ -18,6 +19,9 @@
     <value-type name="QDomDocument">
         <enum-type name="ParseOption" flags="ParseOptions" since="6.5"/>
         <!-- will be replaced in inject code -->
+
+        <value-type name="ParseResult"/>
+
         <modify-function signature="setContent(const QByteArray&amp;,bool,QString*,int*,int*)">
             <modify-argument index="3">
                 <remove-argument/>
diff --git a/sources/pyside6/PySide6/doc/qtqml_functions.rst b/sources/pyside6/PySide6/doc/qtqml_functions.rst
new file mode 100644 (file)
index 0000000..31801b2
--- /dev/null
@@ -0,0 +1,152 @@
+// @snippet qmlregistersingletoninstance
+.. py:function:: qmlRegisterSingletonInstance(pytype: type,\
+                                              uri: str,\
+                                              versionMajor: int,\
+                                              versionMinor: int,\
+                                              typeName: str,\
+                                              instanceObject: object) -> int
+
+   :param type pytype: Python class
+   :param str uri: uri to use while importing the component in QML
+   :param int versionMajor: major version
+   :param int versionMinor: minor version
+   :param str typeName: name exposed to QML
+   :param object instanceObject: singleton object to be registered
+   :return: int (the QML type id)
+
+This function registers a singleton Python object *instanceObject*, with a
+particular *uri* and *typeName*. Its version is a combination of *versionMajor*
+and *versionMinor*. Use this function to register an object of the given type
+*pytype* as a singleton type.
+// @snippet qmlregistersingletoninstance
+
+// @snippet qmlregistersingletontype_qobject_nocallback
+.. py:function:: qmlRegisterSingletonType(pytype: type, uri: str, versionMajor: int, versionMinor: int, typeName: str) -> int
+
+   :param type pytype: Python class
+   :param str uri: uri to use while importing the component in QML
+   :param int versionMajor: major version
+   :param int versionMinor: minor version
+   :param str typeName: name exposed to QML
+   :return: int (the QML type id)
+
+This function registers a Python type as a singleton in the QML system.
+
+Alternatively, the :ref:`QmlSingleton` decorator can be used.
+// @snippet qmlregistersingletontype_qobject_nocallback
+
+// @snippet qmlregistersingletontype_qobject_callback
+.. py:function:: qmlRegisterSingletonType(pytype: type, uri: str, versionMajor: int, versionMinor: int, typeName: str, callback: object) -> int
+
+   :param type pytype: Python class
+   :param str uri: uri to use while importing the component in QML
+   :param int versionMajor: major version
+   :param int versionMinor: minor version
+   :param str typeName: name exposed to QML
+   :param object callback: Python callable (to handle Python type)
+   :return: int (the QML type id)
+
+This function registers a Python type as a singleton in the QML system using
+the provided callback (which gets a QQmlEngine as a parameter) to generate the
+singleton.
+// @snippet qmlregistersingletontype_qobject_callback
+
+// @snippet qmlregistersingletontype_qjsvalue
+.. py:function:: qmlRegisterSingletonType(uri: str, versionMajor: int, versionMinor: int, typeName: str, callback: object) -> int
+
+   :param str uri: uri to use while importing the component in QML
+   :param int versionMajor: major version
+   :param int versionMinor: minor version
+   :param str typeName: name exposed to QML
+   :param object callback: Python callable (to handle QJSValue)
+   :return: int (the QML type id)
+
+This function registers a QJSValue as a singleton in the QML system using the
+provided callback (which gets a QQmlEngine as a parameter) to generate the
+singleton.
+// @snippet qmlregistersingletontype_qjsvalue
+
+// @snippet qmlregistertype
+.. py:function:: qmlRegisterType(pytype: type, uri: str, versionMajor: int, versionMinor: int, qmlName: str) -> int
+
+   :param type pytype: Python class
+   :param str uri: uri to use while importing the component in QML
+   :param int versionMajor: major version
+   :param int versionMinor: minor version
+   :param str qmlName: name exposed to QML
+   :return: int (the QML type id)
+
+This function registers the Python *type* in the QML system with the name
+*qmlName*, in the library imported from *uri* having the version number
+composed from *versionMajor* and *versionMinor*. For example, this registers a
+Python class 'MySliderItem' as a QML type named 'Slider' for version '1.0' of a
+module called 'com.mycompany.qmlcomponents':
+
+   ::
+
+       qmlRegisterType(MySliderItem, "com.mycompany.qmlcomponents", 1, 0, "Slider")
+
+Once this is registered, the type can be used in QML by importing the specified
+module name and version number:
+
+   ::
+
+       import com.mycompany.qmlcomponents 1.0
+
+       Slider { ... }
+
+Note that it's perfectly reasonable for a library to register types to older
+versions than the actual version of the library. Indeed, it is normal for the
+new library to allow QML written to previous versions to continue to work, even
+if more advanced versions of some of its types are available.
+// @snippet qmlregistertype
+
+// @snippet qmlregisteruncreatabletype
+.. py:function:: qmlRegisterUncreatableType(pytype: type, uri: str, versionMajor: int, versionMinor: int, qmlName: str, noCreationReason: str) -> int
+
+   :param type pytype: Python class
+   :param str uri: uri to use while importing the component in QML
+   :param int versionMajor: major version
+   :param int versionMinor: minor version
+   :param str qmlName: name exposed to QML
+   :param str noCreationReason: Error message shown when trying to create the QML type
+   :return: int (the QML type id)
+
+This function registers the Python *type* in the QML system as an uncreatable
+type with the name *qmlName*, in the library imported from *uri* having the
+version number composed from *versionMajor* and *versionMinor*, showing
+*noCreationReason* as an error message when creating the type is attempted. For
+example, this registers a Python class 'MySliderItem' as a QML type named
+'Slider' for version '1.0' of a module called 'com.mycompany.qmlcomponents':
+
+   ::
+       qmlRegisterUncreatableType(MySliderItem, "com.mycompany.qmlcomponents", 1, 0, "Slider", "Slider cannot be created.")
+
+Note that it's perfectly reasonable for a library to register types to older
+versions than the actual version of the library. Indeed, it is normal for the
+new library to allow QML written to previous versions to continue to work, even
+if more advanced versions of some of its types are available.
+
+Alternatively, the :ref:`QmlUncreatable` decorator can be used.
+// @snippet qmlregisteruncreatabletype
+
+// @snippet qqmlengine-singletoninstance-qmltypeid
+Returns the instance of a singleton type that was registered under qmlTypeId.
+For ``QObject``-derived singleton types, the ``QObject`` instance is returned,
+otherwise a ``QJSValue`` or ``None``.
+
+It is recommended to store the QML type id, e.g. as a static member in the
+singleton class. The lookup via qmlTypeId() is costly.
+// @snippet qqmlengine-singletoninstance-qmltypeid
+
+// @snippet qqmlengine-singletoninstance-typename Returns the instance of a
+singleton type named typeName from the module specified by uri.
+For ``QObject``-derived singleton types, the ``QObject`` instance is returned,
+otherwise a ``QJSValue`` or ``None``.
+
+This method can be used as an alternative to calling qmlTypeId followed by the
+id based overload of singletonInstance. This is convenient when one only needs
+to do a one time setup of a singleton; if repeated access to the singleton is
+required, caching its typeId will allow faster subsequent access via the
+type-id based overload.
+// @snippet qqmlengine-singletoninstance-typename
diff --git a/sources/pyside6/PySide6/doc/qtquicktest.rst b/sources/pyside6/PySide6/doc/qtquicktest.rst
new file mode 100644 (file)
index 0000000..9df2af0
--- /dev/null
@@ -0,0 +1,62 @@
+// @snippet quick_test_main_documentation
+
+Sets up the entry point for a Qt Quick Test application.
+The ``name`` argument uniquely identifies this set of tests.
+
+``sys.argv`` should be passed to the ``argv`` argument to ensure
+propagation of the command line arguments.
+
+.. note:: The function assumes that your test sources are in the current
+          directory, unless the ``QUICK_TEST_SOURCE_DIR`` environment
+          variable is set or a directory is passed in ``dir``.
+
+The following snippet demonstrates the use of this function:
+
+.. code-block:: Python
+
+    import sys
+    from PySide6.QtQuickTest import QUICK_TEST_MAIN
+
+    ex = QUICK_TEST_MAIN("example", sys.argv)
+    sys.exit(ex)
+
+
+// @snippet quick_test_main_documentation
+
+// @snippet quick_test_main_with_setup_documentation
+
+Sets up the entry point for a Qt Quick Test application.
+The ``name`` argument uniquely identifies this set of tests.
+
+``sys.argv`` should be passed to the ``argv`` argument to ensure
+propagation of the command line arguments.
+
+This function is identical to ``QUICK_TEST_MAIN()``, except that it takes an
+additional argument ``setup``, the type of a ``QObject``-derived
+class which will be instantiated. With this class, it is possible to define
+additional setup code to execute before running the QML test.
+
+The following snippet demonstrates the use of this function:
+
+.. code-block:: Python
+
+    import sys
+    from PySide6.QtQuickTest import QUICK_TEST_MAIN_WITH_SETUP
+
+    class CustomTestSetup(QObject):
+        def __init__(self, parent=None):
+            super().__init__(parent)
+
+        @Slot(QQmlEngine)
+        def qmlEngineAvailable(self, qmlEngine):
+            pass
+
+    ex = QUICK_TEST_MAIN_WITH_SETUP("qquicktestsetup", CustomTestSetup, sys.argv)
+    sys.exit(ex)
+
+
+.. note:: The function assumes that your test sources are in the current
+          directory, unless the ``QUICK_TEST_SOURCE_DIR`` environment
+          variable is set or a directory is passed in ``dir``.
+
+// @snippet quick_test_main_with_setup_documentation
diff --git a/sources/pyside6/PySide6/doc/qtuitools.rst b/sources/pyside6/PySide6/doc/qtuitools.rst
new file mode 100644 (file)
index 0000000..a8856f1
--- /dev/null
@@ -0,0 +1,68 @@
+// @snippet quiloader-registercustomwidget
+Registers a Python created custom widget to QUiLoader, so it can be recognized
+when loading a `.ui` file. The custom widget type is passed via the
+``customWidgetType`` argument. This is needed when you want to override a
+virtual method of some widget in the interface, since duck punching will not
+work with widgets created by QUiLoader based on the contents of the `.ui` file.
+
+(Remember that
+`duck punching virtual methods is an invitation for your own demise! <https://doc.qt.io/qtforpython/shiboken6/wordsofadvice.html#duck-punching-and-virtual-methods>`_)
+
+Let's see an obvious example. If you want to create a new widget it's probable you'll end up
+overriding :class:`~PySide6.QtGui.QWidget`'s :meth:`~PySide6.QtGui.QWidget.paintEvent` method.
+
+.. code-block:: python
+
+   class Circle(QWidget):
+       def paintEvent(self, event):
+           with QPainter(self) as painter:
+               painter.setPen(self.pen)
+               painter.setBrush(QBrush(self.color))
+               painter.drawEllipse(event.rect().center(), 20, 20)
+
+   # ...
+
+   loader = QUiLoader()
+   loader.registerCustomWidget(Circle)
+   circle = loader.load('circle.ui')
+   circle.show()
+
+   # ...
+// @snippet quiloader-registercustomwidget
+
+// @snippet loaduitype
+.. currentmodule:: PySide6.QtUiTools
+
+loadUiType
+***********
+.. py:function:: loadUiType(uifile: str) -> tuple(object, object)
+
+   :param str uifile: The name of the `.ui` file
+   :return: tuple(object, object)
+
+This function generates and loads a `.ui` file at runtime, and it returns
+a `tuple` containing the reference to the Python class, and the base class.
+
+We recommend not to use this approach as the workflow should be to generate a Python file
+from the `.ui` file, and then import and load it to use it, but we do understand that
+there are some corner cases when such functionality is required.
+
+The internal process relies on `uic` being in the PATH.
+The `pyside6-uic` wrapper uses a shipped `uic` that is located in the
+`site-packages/PySide6/uic`, so PATH needs to be updated to use that if there
+is no `uic` in the system.
+
+A simple use case is::
+
+    from PySide6.QtUiTools import loadUiType
+
+    generated_class, base_class = loadUiType("themewidget.ui")
+    # the values will be:
+    #  (<class '__main__.Ui_ThemeWidgetForm'>, <class 'PySide6.QtWidgets.QWidget'>)
+
+    widget = base_class()
+    form = generated_class()
+    form.setupUi(widget)
+    # form.a_widget_member.a_method_of_member()
+    widget.show()
+// @snippet loaduitype
index 94dc915a09a3d1fec4e9230e4fcd61fe06e616ef..0c206db7265f01bfbe9a780f0e2ebddcb8224e32 100644 (file)
@@ -84,11 +84,9 @@ static PyObject *convertToPrimitiveType(const QVariant &out, int metaTypeId)
         return PyFloat_FromDouble(out.toFloat());
     case QMetaType::Bool:
         if (out.toBool()) {
-            Py_INCREF(Py_True);
-            return Py_True;
+            Py_RETURN_TRUE;
         }
-        Py_INCREF(Py_False);
-        return Py_False;
+        Py_RETURN_FALSE;
     default:
         break;
     }
@@ -269,6 +267,30 @@ static QVariant QVariant_convertToVariantList(PyObject *list)
     }
     return QVariant(lst);
 }
+
+using SpecificConverter = Shiboken::Conversions::SpecificConverter;
+
+static std::optional<SpecificConverter> converterForQtType(const char *typeNameC)
+{
+    // Fix typedef "QGenericMatrix<3,3,float>" -> QMatrix3x3". The reverse
+    // conversion happens automatically in QMetaType::fromName() in
+    // QVariant_resolveMetaType().
+    QByteArrayView typeNameV(typeNameC);
+    if (typeNameV.startsWith("QGenericMatrix<") && typeNameV.endsWith(",float>")) {
+        QByteArray typeName = typeNameV.toByteArray();
+        typeName.remove(1, 7);
+        typeName.remove(7, 1); // '<'
+        typeName.chop(7);
+        typeName.replace(',', 'x');
+        SpecificConverter matrixConverter(typeName.constData());
+        if (matrixConverter)
+            return matrixConverter;
+    }
+    SpecificConverter converter(typeNameC);
+    if (converter)
+        return converter;
+    return std::nullopt;
+}
 // @snippet qvariant-conversion
 
 // @snippet qt-qabs
@@ -284,6 +306,18 @@ PySide::addPostRoutine(%1);
 qAddPostRoutine(PySide::globalPostRoutineCallback);
 // @snippet qt-qaddpostroutine
 
+// @snippet qcompress-buffer
+auto *ptr = reinterpret_cast<uchar*>(Shiboken::Buffer::getPointer(%PYARG_1));
+QByteArray compressed = %FUNCTION_NAME(ptr, %2, %3);
+%PYARG_0 = %CONVERTTOPYTHON[QByteArray](compressed);
+// @snippet qcompress-buffer
+
+// @snippet quncompress-buffer
+auto *ptr = reinterpret_cast<uchar*>(Shiboken::Buffer::getPointer(%PYARG_1));
+QByteArray uncompressed = %FUNCTION_NAME(ptr, %2);
+%PYARG_0 = %CONVERTTOPYTHON[QByteArray](uncompressed);
+// @snippet quncompress-buffer
+
 // @snippet qt-version
 QList<QByteArray> version = QByteArray(qVersion()).split('.');
 PyObject *pyQtVersion = PyTuple_New(3);
@@ -383,10 +417,10 @@ PySide::Feature::init();
 // @snippet qt-init-feature
 
 // @snippet qt-pysideinit
-Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QSTRING_IDX], "unicode");
-Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QSTRING_IDX], "str");
-Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QTCORE_QLIST_QVARIANT_IDX], "QVariantList");
-Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QTCORE_QMAP_QSTRING_QVARIANT_IDX], "QVariantMap");
+Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QString_IDX], "unicode");
+Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QString_IDX], "str");
+Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QtCore_QList_QVariant_IDX], "QVariantList");
+Shiboken::Conversions::registerConverterName(SbkPySide6_QtCoreTypeConverters[SBK_QtCore_QMap_QString_QVariant_IDX], "QVariantMap");
 
 PySide::registerInternalQtConf();
 PySide::init(module);
@@ -508,31 +542,6 @@ if (!PyDateTimeAPI)
 %PYARG_0 = PyDateTime_FromDateAndTime(date.year(), date.month(), date.day(), time.hour(), time.minute(), time.second(), time.msec()*1000);
 // @snippet qdatetime-topython
 
-// @snippet qpoint
-namespace PySide {
-    template<> inline Py_ssize_t hash(const QPoint &v) {
-        return qHash(qMakePair(v.x(), v.y()));
-    }
-};
-// @snippet qpoint
-
-// @snippet qrect
-namespace PySide {
-    template<> inline Py_ssize_t hash(const QRect &r) {
-        const int v[4] = {r.x(), r.y(), r.width(), r.height()};
-        return qHashRange(v, v + 4);
-    }
-};
-// @snippet qrect
-
-// @snippet qsize
-namespace PySide {
-    template<> inline Py_ssize_t hash(const QSize &v) {
-        return qHash(qMakePair(v.width(), v.height()));
-    }
-};
-// @snippet qsize
-
 // @snippet qtime-topython
 if (!PyDateTimeAPI)
     PyDateTime_IMPORT;
@@ -621,20 +630,16 @@ if (ret == nullptr) {
 // @snippet qbytearray-mgetitem
 if (PyIndex_Check(_key)) {
     const Py_ssize_t _i = PyNumber_AsSsize_t(_key, PyExc_IndexError);
-    if (_i < 0 || _i >= %CPPSELF.size()) {
-        PyErr_SetString(PyExc_IndexError, "index out of bounds");
-        return nullptr;
-    }
+    if (_i < 0 || _i >= %CPPSELF.size())
+        return PyErr_Format(PyExc_IndexError, "index out of bounds");
     char res[2] = {%CPPSELF.at(_i), '\0'};
     return PyBytes_FromStringAndSize(res, 1);
 }
 
-if (PySlice_Check(_key) == 0) {
-    PyErr_Format(PyExc_TypeError,
+if (PySlice_Check(_key) == 0)
+    return PyErr_Format(PyExc_TypeError,
                  "list indices must be integers or slices, not %.200s",
                  Py_TYPE(_key)->tp_name);
-    return nullptr;
-}
 
 Py_ssize_t start, stop, step, slicelength;
 if (PySlice_GetIndicesEx(_key, %CPPSELF.size(), &start, &stop, &step, &slicelength) < 0)
@@ -660,6 +665,7 @@ return %CONVERTTOPYTHON[QByteArray](ba);
 // @snippet qbytearray-mgetitem
 
 // @snippet qbytearray-msetitem
+// PYSIDE-2404: Usage of the `get()` function not necessary, the type exists.
 if (PyIndex_Check(_key)) {
     Py_ssize_t _i = PyNumber_AsSsize_t(_key, PyExc_IndexError);
     if (_i == -1 && PyErr_Occurred())
@@ -684,7 +690,8 @@ if (PyIndex_Check(_key)) {
             PyErr_SetString(PyExc_ValueError, "bytearray must be of size 1");
             return -1;
         }
-    } else if (Py_TYPE(_value) == reinterpret_cast<PyTypeObject *>(SbkPySide6_QtCoreTypes[SBK_QBYTEARRAY_IDX])) {
+    } else if (Py_TYPE(_value) == reinterpret_cast<PyTypeObject *>(
+            SbkPySide6_QtCoreTypeStructs[SBK_QByteArray_IDX].type)) {
         if (PyObject_Length(_value) != 1) {
             PyErr_SetString(PyExc_ValueError, "QByteArray must be of size 1");
             return -1;
@@ -721,7 +728,7 @@ if (PySlice_GetIndicesEx(_key, %CPPSELF.size(), &start, &stop, &step, &sliceleng
 Py_ssize_t value_length = 0;
 if (_value != nullptr && _value != Py_None) {
     if (!(PyBytes_Check(_value) || PyByteArray_Check(_value)
-          || Py_TYPE(_value) == reinterpret_cast<PyTypeObject *>(SbkPySide6_QtCoreTypes[SBK_QBYTEARRAY_IDX]))) {
+          || Py_TYPE(_value) == SbkPySide6_QtCoreTypeStructs[SBK_QByteArray_IDX].type)) {
            PyErr_Format(PyExc_TypeError, "bytes, bytearray or QByteArray is required, not %.200s",
                         Py_TYPE(_value)->tp_name);
            return -1;
@@ -778,10 +785,10 @@ static int SbkQByteArray_getbufferproc(PyObject *obj, Py_buffer *view, int flags
     view->len = cppSelf->size();
     view->readonly = 0;
     view->itemsize = 1;
-    view->format = const_cast<char *>("c");
+    view->format = (flags & PyBUF_FORMAT) == PyBUF_FORMAT ? const_cast<char *>("B") : nullptr;
     view->ndim = 1;
     view->shape = (flags & PyBUF_ND) == PyBUF_ND ? &(view->len) : nullptr;
-    view->strides = &view->itemsize;
+    view->strides = (flags & PyBUF_STRIDES) == PyBUF_STRIDES ? &(view->itemsize) : nullptr;
     view->suboffsets = nullptr;
     view->internal = nullptr;
 
@@ -1001,62 +1008,85 @@ auto *ptr = reinterpret_cast<uchar *>(Shiboken::Buffer::getPointer(%PYARG_1, &si
 %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
 // @snippet qtranslator-load
 
-// @snippet qtimer-singleshot-1
-// %FUNCTION_NAME() - disable generation of c++ function call
-(void) %2; // remove warning about unused variable
-Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
-auto *timerType = Shiboken::SbkType<QTimer>();
-auto *pyTimer = timerType->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
-timerType->tp_init(pyTimer, emptyTuple, nullptr);
-
-auto timer = %CONVERTTOCPP[QTimer *](pyTimer);
-Shiboken::AutoDecRef result(
-    PyObject_CallMethod(pyTimer, "connect", "OsOs",
-                        pyTimer,
-                        SIGNAL(timeout()),
-                        %PYARG_2,
-                        %3)
-);
-Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer));
-Py_XDECREF(pyTimer);
-timer->setSingleShot(true);
-timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater);
-timer->start(%1);
-// @snippet qtimer-singleshot-1
-
-// @snippet qtimer-singleshot-2
-// %FUNCTION_NAME() - disable generation of c++ function call
+// @snippet qtimer-singleshot-functorclass
+struct QSingleShotTimerFunctor : public Shiboken::PyObjectHolder
+{
+public:
+    using Shiboken::PyObjectHolder::PyObjectHolder;
+
+    void operator()();
+};
+
+void QSingleShotTimerFunctor::operator()()
+{
+    Shiboken::GilState state;
+    Shiboken::AutoDecRef arglist(PyTuple_New(0));
+    Shiboken::AutoDecRef ret(PyObject_CallObject(object(), arglist));
+    if (Shiboken::Errors::occurred())
+        Shiboken::Errors::storeErrorOrPrint();
+    release(); // single shot
+}
+// @snippet qtimer-singleshot-functorclass
+
+// @snippet qtimer-singleshot-direct-mapping
 Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
-auto *timerType = Shiboken::SbkType<QTimer>();
-auto *pyTimer = timerType->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
-timerType->tp_init(pyTimer, emptyTuple, nullptr);
-QTimer * timer = %CONVERTTOCPP[QTimer *](pyTimer);
-timer->setSingleShot(true);
-
-if (PyObject_TypeCheck(%2, PySideSignalInstance_TypeF())) {
-    PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance *>(%2);
-    Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s", PySide::Signal::getSignature(signalInstance)));
-    Shiboken::AutoDecRef result(
-        PyObject_CallMethod(pyTimer, "connect", "OsOO",
-                            pyTimer,
-                            SIGNAL(timeout()),
-                            PySide::Signal::getObject(signalInstance),
-                            signalSignature.object())
-    );
+%CPPSELF.%FUNCTION_NAME(%1, %2, %3);
+// @snippet qtimer-singleshot-direct-mapping
+
+// @snippet qtimer-singleshot-functor
+auto msec = %1;
+if (msec == 0) {
+    if (PyObject_TypeCheck(%2, PySideSignalInstance_TypeF())) {
+        auto *signal = %PYARG_2;
+        auto cppCallback = [signal]()
+        {
+            Shiboken::GilState state;
+            Shiboken::AutoDecRef ret(PyObject_CallMethod(signal, "emit", "()"));
+            Py_DECREF(signal);
+        };
+
+        Py_INCREF(signal);
+        %CPPSELF.%FUNCTION_NAME(msec, cppCallback);
+    } else {
+        %CPPSELF.%FUNCTION_NAME(msec, QSingleShotTimerFunctor(%PYARG_2));
+    }
 } else {
-    Shiboken::AutoDecRef result(
-        PyObject_CallMethod(pyTimer, "connect", "OsO",
-                            pyTimer,
-                            SIGNAL(timeout()),
-                            %PYARG_2)
-    );
-}
+    // %FUNCTION_NAME() - disable generation of c++ function call
+    Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
+    auto *timerType = Shiboken::SbkType<QTimer>();
+    auto newFunc = reinterpret_cast<newfunc>(PepType_GetSlot(timerType, Py_tp_new));
+    auto initFunc = reinterpret_cast<initproc>(PepType_GetSlot(timerType, Py_tp_init));
+    auto *pyTimer = newFunc(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
+    initFunc(pyTimer, emptyTuple, nullptr);
 
-timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater, Qt::DirectConnection);
-Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer));
-Py_XDECREF(pyTimer);
-timer->start(%1);
-// @snippet qtimer-singleshot-2
+    QTimer * timer = %CONVERTTOCPP[QTimer *](pyTimer);
+    timer->setSingleShot(true);
+
+    if (PyObject_TypeCheck(%2, PySideSignalInstance_TypeF())) {
+        PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance *>(%2);
+        Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s", PySide::Signal::getSignature(signalInstance)));
+        Shiboken::AutoDecRef result(
+            PyObject_CallMethod(pyTimer, "connect", "OsOO",
+                                pyTimer,
+                                SIGNAL(timeout()),
+                                PySide::Signal::getObject(signalInstance),
+                                signalSignature.object())
+        );
+    } else {
+        Shiboken::AutoDecRef result(
+            PyObject_CallMethod(pyTimer, "connect", "OsO",
+                                pyTimer,
+                                SIGNAL(timeout()),
+                                %PYARG_2)
+        );
+    }
+
+    timer->connect(timer, &QTimer::timeout, timer, &QObject::deleteLater, Qt::DirectConnection);
+    Shiboken::Object::releaseOwnership(reinterpret_cast<SbkObject *>(pyTimer));
+    Py_XDECREF(pyTimer);
+    timer->start(msec);
+}
+// @snippet qtimer-singleshot-functor
 
 // @snippet qtimer-singleshot-functor-context
 auto msec = %1;
@@ -1076,8 +1106,8 @@ if (msec == 0) {
 } else {
     Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
     auto *timerType = Shiboken::SbkType<QTimer>();
-    auto newFunc = timerType->tp_new;
-    auto initFunc = timerType->tp_init;
+    auto newFunc = reinterpret_cast<newfunc>(PepType_GetSlot(timerType, Py_tp_new));
+    auto initFunc = reinterpret_cast<initproc>(PepType_GetSlot(timerType, Py_tp_init));
     auto *pyTimer = newFunc(Shiboken::SbkType<QTimer>(), emptyTuple, nullptr);
     initFunc(pyTimer, emptyTuple, nullptr);
 
@@ -1483,15 +1513,23 @@ double in = %CONVERTTOCPP[double](%in);
 // @snippet conversion-sbkobject
 // a class supported by QVariant?
 const QMetaType metaType = QVariant_resolveMetaType(Py_TYPE(%in));
+bool ok = false;
 if (metaType.isValid()) {
     QVariant var(metaType);
-    Shiboken::Conversions::SpecificConverter converter(metaType.name());
-    converter.toCpp(pyIn, var.data());
-    %out = var;
-} else {
-    // If the type was not encountered, return a default PyObjectWrapper
-    %out = QVariant::fromValue(PySide::PyObjectWrapper(%in));
+    auto converterO = converterForQtType(metaType.name());
+    ok = converterO.has_value();
+    if (ok) {
+        converterO.value().toCpp(pyIn, var.data());
+        %out = var;
+    } else {
+        qWarning("%s: Cannot find a converter for \"%s\".",
+                 __FUNCTION__, metaType.name());
+    }
 }
+
+// If the type was not encountered, return a default PyObjectWrapper
+if (!ok)
+    %out = QVariant::fromValue(PySide::PyObjectWrapper(%in));
 // @snippet conversion-sbkobject
 
 // @snippet conversion-pydict
@@ -1589,6 +1627,28 @@ return PyLong_FromVoidPtr(reinterpret_cast<void *>(%in));
 return PySide::qStringToPyUnicode(%in);
 // @snippet return-pyunicode
 
+// @snippet return-pyunicode-from-qlatin1string
+#ifdef Py_LIMITED_API
+return PySide::qStringToPyUnicode(QString::fromLatin1(%in));
+#else
+return PyUnicode_FromKindAndData(PyUnicode_1BYTE_KIND, %in.constData(), %in.size());
+#endif
+// @snippet return-pyunicode-from-qlatin1string
+
+// @snippet qlatin1string-check
+static bool qLatin1StringCheck(PyObject *o)
+{
+    return PyUnicode_CheckExact(o) != 0
+        && _PepUnicode_KIND(o) == PepUnicode_1BYTE_KIND;
+}
+// @snippet qlatin1string-check
+
+// @snippet conversion-pystring-qlatin1string
+const char *data = reinterpret_cast<const char *>(_PepUnicode_DATA(%in));
+const Py_ssize_t len = PyUnicode_GetLength(%in);
+%out = QLatin1String(data, len);
+// @snippet conversion-pystring-qlatin1string
+
 // @snippet return-pyunicode-from-qanystringview
 return PySide::qStringToPyUnicode(%in.toString());
 // @snippet return-pyunicode-from-qanystringview
@@ -1627,11 +1687,10 @@ default:
     break;
 }
 
-Shiboken::Conversions::SpecificConverter converter(cppInRef.typeName());
-if (converter) {
-   void *ptr = cppInRef.data();
-   return converter.toPython(ptr);
-}
+auto converterO = converterForQtType(cppInRef.typeName());
+if (converterO.has_value())
+    return converterO.value().toPython(cppInRef.data());
+
 PyErr_Format(PyExc_RuntimeError, "Can't find converter for '%s'.", %in.typeName());
 return 0;
 // @snippet return-qvariant
@@ -1745,8 +1804,9 @@ if (dataChar == nullptr) {
 // @snippet qdatastream-read-bytes
 
 // @snippet qloggingcategory_to_cpp
+// PYSIDE-2404: Usage of the `get()` function not necessary, the type exists.
     QLoggingCategory *category{nullptr};
-    Shiboken::Conversions::pythonToCppPointer(SbkPySide6_QtCoreTypes[SBK_QLOGGINGCATEGORY_IDX],
+    Shiboken::Conversions::pythonToCppPointer(SbkPySide6_QtCoreTypeStructs[SBK_QLoggingCategory_IDX].type,
     pyArgs[0], &(category));
 // @snippet qloggingcategory_to_cpp
 
@@ -1952,7 +2012,7 @@ Py_INCREF(callable);
     Shiboken::AutoDecRef locale(PyImport_ImportModule("locale"));
     Shiboken::AutoDecRef getLocale(PyObject_GetAttrString(locale, "getlocale"));
     Shiboken::AutoDecRef systemLocale(PyObject_CallObject(getLocale, nullptr));
-    Shiboken::AutoDecRef localeCode(PyTuple_GetItem(systemLocale, 0));
+    PyObject* localeCode = PyTuple_GetItem(systemLocale, 0);
     %RETURN_TYPE %0;
     if (localeCode != Py_None) {
         QString localeCodeStr = PySide::pyStringToQString(localeCode);
@@ -2030,3 +2090,61 @@ Py_BEGIN_ALLOW_THREADS
 Py_END_ALLOW_THREADS
 // @snippet qcoreapplication-requestpermission
 
+// @snippet qlockfile-getlockinfo
+qint64 pid{};
+QString hostname, appname;
+%CPPSELF.%FUNCTION_NAME(&pid, &hostname, &appname);
+%PYARG_0 = PyTuple_New(3);
+PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[qint64](pid));
+PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[QString](hostname));
+PyTuple_SET_ITEM(%PYARG_0, 2, %CONVERTTOPYTHON[QString](appname));
+// @snippet qlockfile-getlockinfo
+
+// @snippet darwin_permission_plugin
+#ifdef Q_OS_DARWIN
+#include<QtCore/qplugin.h>
+// register the static plugin and setup its metadata
+Q_IMPORT_PLUGIN(QDarwinCameraPermissionPlugin)
+Q_IMPORT_PLUGIN(QDarwinMicrophonePermissionPlugin)
+Q_IMPORT_PLUGIN(QDarwinBluetoothPermissionPlugin)
+Q_IMPORT_PLUGIN(QDarwinContactsPermissionPlugin)
+Q_IMPORT_PLUGIN(QDarwinCalendarPermissionPlugin)
+#endif
+// @snippet darwin_permission_plugin
+
+// @snippet qt-modifier
+PyObject *_inputDict = PyDict_New();
+// Note: The builtins line is no longer needed since Python 3.10. Undocumented!
+PyDict_SetItemString(_inputDict, "__builtins__", PyEval_GetBuiltins());
+PyDict_SetItemString(_inputDict, "QtCore", module);
+PyDict_SetItemString(_inputDict, "Qt", reinterpret_cast<PyObject *>(pyType));
+// Explicitly not dereferencing the result.
+PyRun_String(R"PY(if True:
+    from enum import Flag
+    from textwrap import dedent
+    from warnings import warn
+    # QtCore and Qt come as globals.
+
+    def func_or(self, other):
+        if isinstance(self, Flag) and isinstance(other, Flag):
+            # this is normal or-ing flags together
+            return Qt.KeyboardModifier(self.value | other.value)
+        return QtCore.QKeyCombination(self, other)
+
+    def func_add(self, other):
+        warn(dedent(f"""
+            The "+" operator is deprecated in Qt For Python 6.0 .
+            Please use "|" instead."""), stacklevel=2)
+        return func_or(self, other)
+
+    Qt.KeyboardModifier.__or__ = func_or
+    Qt.KeyboardModifier.__ror__ = func_or
+    Qt.Modifier.__or__ = func_or
+    Qt.Modifier.__ror__ = func_or
+    Qt.KeyboardModifier.__add__ = func_add
+    Qt.KeyboardModifier.__radd__ = func_add
+    Qt.Modifier.__add__ = func_add
+    Qt.Modifier.__radd__ = func_add
+
+)PY", Py_file_input, _inputDict, _inputDict);
+// @snippet qt-modifier
index cf1a10eba803c16337a8549c77492977056da304..b5a5db799ff41edd703b60ecd2ff175ed343919d 100644 (file)
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 // @snippet graphs-qsurfacedataproxy-resetarraynp
-auto *data = QtGraphsHelper::surfaceDataFromNp(%1, %2, %3, %4, %5);
+auto data = QtGraphsHelper::surfaceDataFromNp(%1, %2, %3, %4, %5);
 // %CPPSELF.%FUNCTION_NAME
 %CPPSELF.resetArray(data);
 // @snippet graphs-qsurfacedataproxy-resetarraynp
index e38684a7f9700596b39006bf6e408cb9fda92f78..5c860a2bfc8caf0f6dbd88f269cb24d6f993557e 100644 (file)
@@ -6,7 +6,9 @@
  ********************************************************************/
 
 // @snippet gui-declarations
+QT_BEGIN_NAMESPACE
 void qt_set_sequence_auto_mnemonic(bool);
+QT_END_NAMESPACE
 // @snippet gui-declarations
 
 // @snippet qaccessible-pysidefactory
@@ -781,12 +783,45 @@ auto *cppResult = new QtGuiHelper::QOverrideCursorGuard();
 Shiboken::Object::getOwnership(%PYARG_0); // Ensure the guard is removed
 // @snippet qguiapplication-setoverridecursor
 
+// @snippet qguiapplication-nativeInterface
+bool hasNativeApp = false;
+#if QT_CONFIG(xcb)
+if (auto *x11App = %CPPSELF.nativeInterface<QNativeInterface::QX11Application>()) {
+    hasNativeApp = true;
+    %PYARG_0 = %CONVERTTOPYTHON[QNativeInterface::QX11Application*](x11App);
+}
+#endif
+if (!hasNativeApp) {
+    Py_INCREF(Py_None);
+    %PYARG_0 = Py_None;
+}
+// @snippet qguiapplication-nativeInterface
+
 // @snippet qscreen-grabWindow
 WId id = %1;
 %RETURN_TYPE retval = %CPPSELF.%FUNCTION_NAME(id, %2, %3, %4, %5);
 %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](retval);
 // @snippet qscreen-grabWindow
 
+// @snippet qscreen-nativeInterface
+bool hasNativeScreen = false;
+#ifdef Q_OS_WIN
+if (auto *winScreen = %CPPSELF.nativeInterface<QNativeInterface::QWindowsScreen>()) {
+    hasNativeScreen = true;
+    %PYARG_0 = %CONVERTTOPYTHON[QNativeInterface::QWindowsScreen*](winScreen);
+}
+#endif
+if (!hasNativeScreen) {
+    Py_INCREF(Py_None);
+    %PYARG_0 = Py_None;
+}
+// @snippet qscreen-nativeInterface
+
+// @snippet qx11application-resource-ptr
+ auto *resource = %CPPSELF.%FUNCTION_NAME();
+%PYARG_0 = PyLong_FromVoidPtr(resource);
+// @snippet qx11application-resource-ptr
+
 // @snippet qwindow-fromWinId
 WId id = %1;
 %RETURN_TYPE retval = %CPPSELF.%FUNCTION_NAME(id);
@@ -854,15 +889,31 @@ else
 %PYARG_0 = %CONVERTTOPYTHON[int](cppResult);
 // @snippet qdrag-exec-arg2
 
+// @snippet qquaternion-getaxisandangle-vector3d-float
+QVector3D outVec{};
+float angle{};
+%CPPSELF.%FUNCTION_NAME(&outVec, &angle);
+%PYARG_0 = PyTuple_New(2);
+PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[QVector3D](outVec));
+PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[float](angle));
+// @snippet qquaternion-getaxisandangle-vector3d-float
+
+// @snippet qquaternion-geteulerangles
+float pitch{}, yaw{}, roll{};
+%CPPSELF.%FUNCTION_NAME(&pitch, &yaw, &roll);
+%PYARG_0 = PyTuple_New(3);
+PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[float](pitch));
+PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[float](yaw));
+PyTuple_SET_ITEM(%PYARG_0, 2, %CONVERTTOPYTHON[float](roll));
+// @snippet qquaternion-geteulerangles
+
 // @snippet qregion-len
 return %CPPSELF.rectCount();
 // @snippet qregion-len
 
 // @snippet qregion-getitem
-if (_i < 0 || _i >= %CPPSELF.rectCount()) {
-    PyErr_SetString(PyExc_IndexError, "index out of bounds");
-    return nullptr;
-}
+if (_i < 0 || _i >= %CPPSELF.rectCount())
+    return PyErr_Format(PyExc_IndexError, "index out of bounds");
 
 const QRect cppResult = *(%CPPSELF.cbegin() + _i);
 return %CONVERTTOPYTHON[QRect](cppResult);
index 3d46619fddae86e6e88254ac2cebe397e1bdb1a7..ac8434b97b1a2a414525a4a217fa7340c67b15f5 100644 (file)
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 // @snippet qvideoframe-bits
+#include "object.h"
 %BEGIN_ALLOW_THREADS
 %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%1);
 %END_ALLOW_THREADS
@@ -20,3 +21,8 @@ const unsigned char *data = %CPPSELF.%FUNCTION_NAME<unsigned char>();
 const auto size = %CPPSELF.byteCount();
 %PYARG_0 = Shiboken::Buffer::newObject(data, size);
 // @snippet qaudiobuffer-const-data
+
+// @snippet qtaudio-namespace-compatibility-alias
+Py_INCREF(pyType);
+PyModule_AddObject(module, "QtAudio", reinterpret_cast<PyObject *>(pyType));
+// @snippet qtaudio-namespace-compatibility-alias
index f00780b4025d89d4ca8f379af7cfb389af236929..f635f4671cf2995254bb84d7c476357b7674fc01 100644 (file)
@@ -15,20 +15,28 @@ PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[QHostAddress](ha));
 PyTuple_SET_ITEM(%PYARG_0, 2, %CONVERTTOPYTHON[quint16](port));
 // @snippet qudpsocket-readdatagram
 
-// @snippet qhostinfo-lookuphost-callable
-auto *callable = %PYARG_2;
-auto cppCallback = [callable](const QHostInfo &hostInfo)
+// @snippet qhostinfo-lookuphost-functor
+struct QHostInfoFunctor : public Shiboken::PyObjectHolder
+{
+public:
+    using Shiboken::PyObjectHolder::PyObjectHolder;
+
+    void operator()(const QHostInfo &hostInfo);
+};
+
+void QHostInfoFunctor::operator()(const QHostInfo &hostInfo)
 {
     Shiboken::GilState state;
     Shiboken::AutoDecRef arglist(PyTuple_New(1));
     auto *pyHostInfo = %CONVERTTOPYTHON[QHostInfo](hostInfo);
     PyTuple_SET_ITEM(arglist.object(), 0, pyHostInfo);
-    Shiboken::AutoDecRef ret(PyObject_CallObject(callable, arglist));
-    Py_DECREF(callable);
-};
+    Shiboken::AutoDecRef ret(PyObject_CallObject(object(), arglist));
+    release(); // single shot
+}
+// @snippet qhostinfo-lookuphost-functor
 
-Py_INCREF(callable);
-%CPPSELF.%FUNCTION_NAME(%1, cppCallback);
+// @snippet qhostinfo-lookuphost-callable
+%CPPSELF.%FUNCTION_NAME(%1, QHostInfoFunctor(%PYARG_2));
 // @snippet qhostinfo-lookuphost-callable
 
 // @snippet qipv6address-len
@@ -58,3 +66,65 @@ quint8 item = %CONVERTTOCPP[quint8](_value);
 %CPPSELF.c[_i] = item;
 return 0;
 // @snippet qipv6address-setitem
+
+// @snippet qrestaccessmanager-functor
+class QRestFunctor
+{
+public:
+    explicit QRestFunctor(PyObject *callable) noexcept : m_callable(callable)
+    {
+        Py_INCREF(callable);
+    }
+
+    void operator()(QRestReply &restReply);
+
+private:
+    PyObject *m_callable;
+};
+
+void QRestFunctor::operator()(QRestReply &restReply)
+{
+    Q_ASSERT(m_callable);
+    Shiboken::GilState state;
+    Shiboken::AutoDecRef arglist(PyTuple_New(1));
+    auto *restReplyPtr = &restReply;
+    auto *pyRestReply = %CONVERTTOPYTHON[QRestReply*](restReplyPtr);
+    PyTuple_SET_ITEM(arglist.object(), 0, pyRestReply);
+    Shiboken::AutoDecRef ret(PyObject_CallObject(m_callable, arglist));
+    Py_DECREF(m_callable);
+    m_callable = nullptr;
+}
+// @snippet qrestaccessmanager-functor
+
+// @snippet qrestaccessmanager-callback
+auto *networkReply = %CPPSELF.%FUNCTION_NAME(%1, %2, QRestFunctor(%PYARG_3));
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](networkReply);
+// @snippet qrestaccessmanager-callback
+
+// @snippet qrestaccessmanager-data-callback
+auto *networkReply = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, QRestFunctor(%PYARG_4));
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](networkReply);
+// @snippet qrestaccessmanager-data-callback
+
+// @snippet qrestaccessmanager-method-data-callback
+auto *networkReply = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, QRestFunctor(%PYARG_5));
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](networkReply);
+// @snippet qrestaccessmanager-method-data-callback
+
+// @snippet qrestreply-readjson
+QJsonParseError jsonParseError;
+std::optional<QJsonDocument> documentOptional = %CPPSELF.%FUNCTION_NAME(&jsonParseError);
+
+PyObject *pyDocument{};
+if (documentOptional.has_value()) {
+    const auto &document = documentOptional.value();
+    pyDocument = %CONVERTTOPYTHON[QJsonDocument](document);
+} else {
+    pyDocument = Py_None;
+    Py_INCREF(Py_None);
+}
+
+%PYARG_0 = PyTuple_New(2);
+PyTuple_SetItem(%PYARG_0, 0, pyDocument);
+PyTuple_SetItem(%PYARG_0, 1, %CONVERTTOPYTHON[QJsonParseError](jsonParseError));
+// @snippet qrestreply-readjson
index f390605d2a8545cfa78346ec4a0a2195664a27fd..7877a8dd5cc4f15b25744a9fd9623b89231bcc7a 100644 (file)
@@ -1,12 +1,21 @@
 // Copyright (C) 2022 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
-// @snippet qabstractoauth-setmodifyparametersfunction
-auto callable = %PYARG_1;
-auto callback = [callable](QAbstractOAuth::Stage stage, QMultiMap<QString, QVariant>* dictPointer) -> void
+// @snippet qabstractoauth-lookuphost-functor
+struct QAbstractOAuthModifyFunctor : public Shiboken::PyObjectHolder
+{
+public:
+    using Shiboken::PyObjectHolder::PyObjectHolder;
+
+    void operator()(QAbstractOAuth::Stage stage, QMultiMap<QString, QVariant>* dictPointer);
+};
+
+void QAbstractOAuthModifyFunctor::operator()(QAbstractOAuth::Stage stage,
+                                             QMultiMap<QString, QVariant>* dictPointer)
 {
+    auto *callable = object();
     if (!PyCallable_Check(callable)) {
-        qWarning("Argument 1 of %FUNCTION_NAME must be a callable.");
+        qWarning("Argument 1 of setModifyParametersFunction() must be a callable.");
         return;
     }
     Shiboken::GilState state;
@@ -26,12 +35,10 @@ auto callback = [callable](QAbstractOAuth::Stage stage, QMultiMap<QString, QVari
             dictPointer->replace(cppKey, cppValue);
         }
     }
+}
+// @snippet qabstractoauth-lookuphost-functor
 
-    Py_DECREF(callable);
-    return;
-
-};
-Py_INCREF(callable);
-%CPPSELF.%FUNCTION_NAME(callback);
+// @snippet qabstractoauth-setmodifyparametersfunction
+%CPPSELF.%FUNCTION_NAME(QAbstractOAuthModifyFunctor(%PYARG_1));
 // @snippet qabstractoauth-setmodifyparametersfunction
 
diff --git a/sources/pyside6/PySide6/glue/qtpositioning.cpp b/sources/pyside6/PySide6/glue/qtpositioning.cpp
new file mode 100644 (file)
index 0000000..91c331c
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/*********************************************************************
+ * INJECT CODE
+ ********************************************************************/
+
+// @snippet darwin_location_permission_plugin
+#ifdef Q_OS_DARWIN
+#include<QtCore/qplugin.h>
+// register the static plugin and setup its metadata
+Q_IMPORT_PLUGIN(QDarwinLocationPermissionPlugin)
+#endif
+// @snippet darwin_location_permission_plugin
index 20bcfff4533349d8d42160f5af7d3d293f5c854b..a56db8de666b6baaa21057a523fb077a82218563 100644 (file)
@@ -62,3 +62,29 @@ return %CONVERTTOPYTHON[%RETURN_TYPE](retval);
 // @snippet qmlsingleton
 %PYARG_0 = PySide::Qml::qmlSingletonMacro(%ARGUMENT_NAMES);
 // @snippet qmlsingleton
+
+// @snippet qqmlengine-singletoninstance-qmltypeid
+QJSValue instance = %CPPSELF.singletonInstance<QJSValue>(%1);
+if (instance.isNull()) {
+    Py_INCREF(Py_None);
+    %PYARG_0 = Py_None;
+} else if (instance.isQObject()) {
+    QObject *result = instance.toQObject();
+    %PYARG_0 = %CONVERTTOPYTHON[QObject *](result);
+} else  {
+    %PYARG_0 = %CONVERTTOPYTHON[QJSValue](instance);
+}
+// @snippet qqmlengine-singletoninstance-qmltypeid
+
+// @snippet qqmlengine-singletoninstance-typename
+QJSValue instance = %CPPSELF.singletonInstance<QJSValue>(%1, %2);
+if (instance.isNull()) {
+    Py_INCREF(Py_None);
+    %PYARG_0 = Py_None;
+} else if (instance.isQObject()) {
+    QObject *result = instance.toQObject();
+    %PYARG_0 = %CONVERTTOPYTHON[QObject *](result);
+} else  {
+    %PYARG_0 = %CONVERTTOPYTHON[QJSValue](instance);
+}
+// @snippet qqmlengine-singletoninstance-typename
diff --git a/sources/pyside6/PySide6/glue/qtquicktest.cpp b/sources/pyside6/PySide6/glue/qtquicktest.cpp
new file mode 100644 (file)
index 0000000..f41735d
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/*********************************************************************
+ * INJECT CODE
+ ********************************************************************/
+
+// @snippet call-quick-test-main
+static int callQuickTestMain(const QString &name, QObject *setup,
+                             QStringList argv, QString dir)
+{
+    if (dir.isEmpty())
+        dir = QDir::currentPath();
+    if (argv.isEmpty())
+        argv.append(name);
+
+    std::vector<QByteArray> argvB;
+    std::vector<char *> argvC;
+    const auto argc = argv.size();
+    argvB.reserve(argc);
+    argvC.reserve(argc);
+    for (const auto &arg : argv) {
+        argvB.emplace_back(arg.toUtf8());
+        argvC.push_back(argvB.back().data());
+    }
+
+    return quick_test_main_with_setup(int(argc), argvC.data(),
+                                      name.toUtf8().constData(),
+                                      dir.toUtf8().constData(), setup);
+}
+// @snippet call-quick-test-main
+
+// @snippet quick-test-main
+const int exitCode = callQuickTestMain(%1, nullptr, %2, %3);
+%PYARG_0 = %CONVERTTOPYTHON[int](exitCode);
+// @snippet quick-test-main
+
+// @snippet quick-test-main_with_setup
+Shiboken::AutoDecRef pySetupObject(PyObject_CallObject(reinterpret_cast<PyObject *>(%2), nullptr));
+if (pySetupObject.isNull() || PyErr_Occurred() != nullptr)
+    return nullptr;
+
+/// Convenience to convert a PyObject to QObject
+QObject *setupObject = PySide::convertToQObject(pySetupObject.object(), true /* raiseError */);
+if (setupObject == nullptr)
+    return nullptr;
+
+const int exitCode = callQuickTestMain(%1, setupObject, %3, %4);
+%PYARG_0 = %CONVERTTOPYTHON[int](exitCode);
+// @snippet quick-test-main_with_setup
index c87cf9e7bcd580c77d2e25d654b389129811d590..1835ed096856fe55e42a19f3900619e2aa946659 100644 (file)
@@ -45,7 +45,7 @@ static PyObject *QUiLoadedLoadUiFromDevice(QUiLoader *self, QIODevice *dev, QWid
     }
 
     if (!PyErr_Occurred())
-        PyErr_SetString(PyExc_RuntimeError, "Unable to open/read ui device");
+        PyErr_Format(PyExc_RuntimeError, "Unable to open/read ui device");
     return nullptr;
 }
 
@@ -87,15 +87,15 @@ char *arg1 = PyBytes_AsString(strObj);
 QByteArray uiFileName(arg1);
 Py_DECREF(strObj);
 
-QFile uiFile(QString::fromUtf8(uiFileName));
-
-if (!uiFile.exists()) {
-    qCritical().noquote() << "File" << uiFileName << "does not exists";
+if (uiFileName.isEmpty()) {
+    qCritical() << "Error converting the UI filename to QByteArray";
     Py_RETURN_NONE;
 }
 
-if (uiFileName.isEmpty()) {
-    qCritical() << "Error converting the UI filename to QByteArray";
+QFile uiFile(QString::fromUtf8(uiFileName));
+
+if (!uiFile.exists()) {
+    qCritical().noquote() << "File" << uiFileName << "does not exist";
     Py_RETURN_NONE;
 }
 
@@ -107,18 +107,26 @@ QStringList uicArgs = {QString::fromUtf8(uiFileName)};
 
 QProcess uicProcess;
 uicProcess.start(uicBin, uicArgs);
-if (!uicProcess.waitForFinished()) {
-    qCritical() << "Cannot run 'pyside6-uic': " << uicProcess.errorString() << " - "
-                << "Exit status " << uicProcess.exitStatus()
-                << " (" << uicProcess.exitCode() << ")\n"
-                << "Check if 'pyside6-uic' is in PATH";
+if (!uicProcess.waitForStarted()) {
+    qCritical().noquote() << "Cannot run '" << uicBin << "': "
+        << uicProcess.errorString() << " - Check if 'pyside6-uic' is in PATH";
     Py_RETURN_NONE;
 }
+
+if (!uicProcess.waitForFinished()
+    || uicProcess.exitStatus() != QProcess::NormalExit
+    || uicProcess.exitCode() != 0) {
+    qCritical().noquote() << '\'' << uicBin << "' failed: "
+        << uicProcess.errorString() << " - Exit status " << uicProcess.exitStatus()
+        << " (" << uicProcess.exitCode() << ")\n";
+    Py_RETURN_NONE;
+}
+
 QByteArray uiFileContent = uicProcess.readAllStandardOutput();
 QByteArray errorOutput = uicProcess.readAllStandardError();
 
 if (!errorOutput.isEmpty()) {
-    qCritical().noquote() << errorOutput;
+    qCritical().noquote() << '\'' << uicBin << "' failed: " << errorOutput;
     Py_RETURN_NONE;
 }
 
@@ -142,8 +150,8 @@ QXmlStreamReader reader(&uiFile);
 while (!reader.atEnd() && baseClassName.isEmpty() && className.isEmpty()) {
     auto token = reader.readNext();
     if (token == QXmlStreamReader::StartElement && reader.name() == u"widget") {
-        baseClassName = reader.attributes().value(QLatin1String("class")).toUtf8();
-        className = reader.attributes().value(QLatin1String("name")).toUtf8();
+        baseClassName = reader.attributes().value(QLatin1StringView("class")).toUtf8();
+        className = reader.attributes().value(QLatin1StringView("name")).toUtf8();
     }
 }
 
index 0a0a00ec8231798607de0f3b1eb3d5cbe802b15e..76a7c6d73359802ba47878996cce5c29a0b2662f 100644 (file)
@@ -1,36 +1,64 @@
 // Copyright (C) 2022 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
-// @snippet qwebenginecookiestore-setcookiefilter
-auto callable = %PYARG_1;
-auto callback = [callable](const QWebEngineCookieStore::FilterRequest& filterRequest) -> bool
+// @snippet qwebenginecookiestore-functor
+struct QWebEngineCookieFilterFunctor : public Shiboken::PyObjectHolder
+{
+    using Shiboken::PyObjectHolder::PyObjectHolder;
+
+    bool operator()(const QWebEngineCookieStore::FilterRequest& filterRequest) const;
+};
+
+bool QWebEngineCookieFilterFunctor::operator()(const QWebEngineCookieStore::FilterRequest &
+                                               filterRequest) const
 {
     Shiboken::GilState state;
     Shiboken::AutoDecRef arglist(PyTuple_New(1));
     PyTuple_SET_ITEM(arglist, 0,
-                    %CONVERTTOPYTHON[QWebEngineCookieStore::FilterRequest](filterRequest));
-    Py_INCREF(callable);
-    Shiboken::AutoDecRef ret(PyObject_CallObject(callable, arglist));
-    Py_DECREF(callable);
+                     %CONVERTTOPYTHON[QWebEngineCookieStore::FilterRequest](filterRequest));
+    Shiboken::AutoDecRef ret(PyObject_CallObject(object(), arglist));
     return ret.object() == Py_True;
-};
+}
+// @snippet qwebenginecookiestore-functor
 
-%CPPSELF.%FUNCTION_NAME(callback);
+// @snippet qwebenginecookiestore-setcookiefilter
+%CPPSELF.%FUNCTION_NAME(QWebEngineCookieFilterFunctor(%PYARG_1));
 // @snippet qwebenginecookiestore-setcookiefilter
 
-// @snippet qwebengineprofile-setnotificationpresenter
-auto callable = %PYARG_1;
-auto callback = [callable](std::unique_ptr<QWebEngineNotification> webEngineNotification) -> void
+// @snippet qwebengineprofile-functor
+struct QWebEngineNotificationFunctor : public Shiboken::PyObjectHolder
+{
+    using Shiboken::PyObjectHolder::PyObjectHolder;
+
+    void operator()(std::unique_ptr<QWebEngineNotification> webEngineNotification);
+};
+
+void QWebEngineNotificationFunctor::operator()
+    (std::unique_ptr<QWebEngineNotification> webEngineNotification)
 {
     Shiboken::GilState state;
     Shiboken::AutoDecRef arglist(PyTuple_New(1));
     auto *notification = webEngineNotification.release();
     PyTuple_SET_ITEM(arglist.object(), 0,
                      %CONVERTTOPYTHON[QWebEngineNotification*](notification));
-    Py_INCREF(callable);
-    Shiboken::AutoDecRef ret(PyObject_CallObject(callable, arglist));
-    Py_DECREF(callable);
+    Shiboken::AutoDecRef ret(PyObject_CallObject(object(), arglist));
 };
+// @snippet qwebengineprofile-functor
 
-%CPPSELF.%FUNCTION_NAME(callback);
 // @snippet qwebengineprofile-setnotificationpresenter
+%CPPSELF.%FUNCTION_NAME(QWebEngineNotificationFunctor(%PYARG_1));
+// @snippet qwebengineprofile-setnotificationpresenter
+
+// @snippet qwebenginepage-javascriptprompt-virtual-redirect
+std::pair<bool, QString> resultPair = javaScriptPromptPyOverride(gil, pyOverride.object(), securityOrigin, msg, defaultValue);
+result->assign(resultPair.second);
+return resultPair.first;
+// @snippet qwebenginepage-javascriptprompt-virtual-redirect
+
+// @snippet qwebenginepage-javascriptprompt-return
+QString str;
+%RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, &str);
+%PYARG_0 = PyTuple_New(2);
+PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%RETURN_TYPE](retval_));
+PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[QString](str));
+// @snippet qwebenginepage-javascriptprompt-return
index 9eaf750d4e79cce27f61fc2b86d8a3397d437010..f886106cf4bfc57c8911b5f4adfc094c158663f1 100644 (file)
@@ -217,11 +217,21 @@ if (_widget) {
 #ifndef _QLAYOUT_HELP_FUNCTIONS_
 #define _QLAYOUT_HELP_FUNCTIONS_ // Guard for jumbo builds
 
+static const char msgInvalidParameterAdd[] =
+    "Invalid parameter None passed to addLayoutOwnership().";
+static const char msgInvalidParameterRemoval[] =
+    "Invalid parameter None passed to removeLayoutOwnership().";
+
 void addLayoutOwnership(QLayout *layout, QLayoutItem *item);
 void removeLayoutOwnership(QLayout *layout, QWidget *widget);
 
 inline void addLayoutOwnership(QLayout *layout, QWidget *widget)
 {
+    if (layout == nullptr || widget == nullptr) {
+        PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterAdd);
+        return;
+    }
+
     //transfer ownership to parent widget
     QWidget *lw = layout->parentWidget();
     QWidget *pw = widget->parentWidget();
@@ -248,6 +258,11 @@ inline void addLayoutOwnership(QLayout *layout, QWidget *widget)
 
 inline void addLayoutOwnership(QLayout *layout, QLayout *other)
 {
+    if (layout == nullptr || other == nullptr) {
+        PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterAdd);
+        return;
+    }
+
     //transfer all children widgets from other to layout parent widget
     QWidget *parent = layout->parentWidget();
     if (!parent) {
@@ -274,8 +289,11 @@ inline void addLayoutOwnership(QLayout *layout, QLayout *other)
 
 inline void addLayoutOwnership(QLayout *layout, QLayoutItem *item)
 {
-    if (!item)
+
+    if (layout == nullptr || item == nullptr) {
+        PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterAdd);
         return;
+    }
 
     if (QWidget *w = item->widget()) {
         addLayoutOwnership(layout, w);
@@ -291,6 +309,11 @@ inline void addLayoutOwnership(QLayout *layout, QLayoutItem *item)
 
 static void removeWidgetFromLayout(QLayout *layout, QWidget *widget)
 {
+    if (layout == nullptr || widget == nullptr) {
+        PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterRemoval);
+        return;
+    }
+
     if (QWidget *parent = widget->parentWidget()) {
         //give the ownership to parent
         Shiboken::AutoDecRef pyParent(%CONVERTTOPYTHON[QWidget *](parent));
@@ -308,9 +331,8 @@ static void removeWidgetFromLayout(QLayout *layout, QWidget *widget)
 
 inline void removeLayoutOwnership(QLayout *layout, QLayoutItem *item)
 {
-
-    if (item == nullptr) {
-        PyErr_Format(PyExc_RuntimeError, "Item for removal from layout is None, or invalid.");
+    if (layout == nullptr || item == nullptr) {
+        PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterRemoval);
         return;
     }
 
@@ -329,8 +351,10 @@ inline void removeLayoutOwnership(QLayout *layout, QLayoutItem *item)
 
 inline void removeLayoutOwnership(QLayout *layout, QWidget *widget)
 {
-    if (!widget)
+    if (layout == nullptr || widget == nullptr) {
+        PyErr_SetString(PyExc_RuntimeError, msgInvalidParameterRemoval);
         return;
+    }
 
     for (int i = 0, i_max = layout->count(); i < i_max; ++i) {
         QLayoutItem *item = layout->itemAt(i);
@@ -347,9 +371,10 @@ inline void removeLayoutOwnership(QLayout *layout, QWidget *widget)
 %CPPSELF.setAlignment(%1);
 // @snippet qlayout-setalignment
 
-// @snippet addownership-0
-addLayoutOwnership(%CPPSELF, %0);
-// @snippet addownership-0
+// @snippet addownership-item-at
+if (%0 != nullptr)
+    addLayoutOwnership(%CPPSELF, %0);
+// @snippet addownership-item-at
 
 // @snippet addownership-1
 addLayoutOwnership(%CPPSELF, %1);
@@ -522,15 +547,20 @@ Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(%PYSELF), "__style
 // @snippet qwidget-style
 QStyle *myStyle = %CPPSELF->style();
 if (myStyle && qApp) {
-%PYARG_0 = %CONVERTTOPYTHON[QStyle *](myStyle);
+    bool keepReference = true;
+    %PYARG_0 = %CONVERTTOPYTHON[QStyle *](myStyle);
     QStyle *appStyle = qApp->style();
     if (appStyle == myStyle) {
         Shiboken::AutoDecRef pyApp(%CONVERTTOPYTHON[QApplication *](qApp));
-        Shiboken::Object::setParent(pyApp, %PYARG_0);
-        Shiboken::Object::releaseOwnership(%PYARG_0);
-    } else {
-        Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(%PYSELF), "__style__",  %PYARG_0);
+        // Do not set parentship when qApp is embedded
+        if (Shiboken::Object::wasCreatedByPython(reinterpret_cast<SbkObject *>(pyApp.object()))) {
+            Shiboken::Object::setParent(pyApp, %PYARG_0);
+            Shiboken::Object::releaseOwnership(%PYARG_0);
+            keepReference = false;
+        }
     }
+    if (keepReference)
+        Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(%PYSELF), "__style__",  %PYARG_0);
 }
 // @snippet qwidget-style
 
@@ -709,49 +739,49 @@ const char *styleOptionType(const QStyleOption *o)
     case QStyleOption::SO_Default:
         break;
     case QStyleOption::SO_FocusRect:
-        return "StyleOptionFocusRect";
+        return "QStyleOptionFocusRect";
     case QStyleOption::SO_Button:
-        return "StyleOptionButton";
+        return "QStyleOptionButton";
     case QStyleOption::SO_Tab:
-        return "StyleOptionTab";
+        return "QStyleOptionTab";
     case QStyleOption::SO_MenuItem:
-        return "StyleOptionMenuItem";
+        return "QStyleOptionMenuItem";
     case QStyleOption::SO_Frame:
-        return "StyleOptionFrame";
+        return "QStyleOptionFrame";
     case QStyleOption::SO_ProgressBar:
-        return "StyleOptionProgressBar";
+        return "QStyleOptionProgressBar";
     case QStyleOption::SO_ToolBox:
-        return "StyleOptionToolBox";
+        return "QStyleOptionToolBox";
     case QStyleOption::SO_Header:
-        return "StyleOptionHeader";
+        return "QStyleOptionHeader";
     case QStyleOption::SO_DockWidget:
-        return "StyleOptionDockWidget";
+        return "QStyleOptionDockWidget";
     case QStyleOption::SO_ViewItem:
-        return "StyleOptionViewItem";
+        return "QStyleOptionViewItem";
     case QStyleOption::SO_TabWidgetFrame:
-        return "StyleOptionTabWidgetFrame";
+        return "QStyleOptionTabWidgetFrame";
     case QStyleOption::SO_TabBarBase:
-        return "StyleOptionTabBarBase";
+        return "QStyleOptionTabBarBase";
     case QStyleOption::SO_RubberBand:
-        return "StyleOptionRubberBand";
+        return "QStyleOptionRubberBand";
     case QStyleOption::SO_ToolBar:
-        return "StyleOptionToolBar";
+        return "QStyleOptionToolBar";
     case QStyleOption::SO_GraphicsItem:
-        return "StyleOptionGraphicsItem";
+        return "QStyleOptionGraphicsItem";
     case QStyleOption::SO_Slider:
-        return "StyleOptionSlider";
+        return "QStyleOptionSlider";
     case QStyleOption::SO_SpinBox:
-        return "StyleOptionSpinBox";
+        return "QStyleOptionSpinBox";
     case QStyleOption::SO_ToolButton:
-        return "StyleOptionToolButton";
+        return "QStyleOptionToolButton";
     case QStyleOption::SO_ComboBox:
-        return "StyleOptionComboBox";
+        return "QStyleOptionComboBox";
     case QStyleOption::SO_TitleBar:
-        return "StyleOptionTitleBar";
+        return "QStyleOptionTitleBar";
     case QStyleOption::SO_GroupBox:
-        return "StyleOptionGroupBox";
+        return "QStyleOptionGroupBox";
     case QStyleOption::SO_SizeGrip:
-        return "StyleOptionSizeGrip";
+        return "QStyleOptionSizeGrip";
     default:
         break;
     }
@@ -762,10 +792,8 @@ const char *styleOptionType(const QStyleOption *o)
 // @snippet qwizardpage-registerfield
 auto *signalInst = reinterpret_cast<PySideSignalInstance *>(%PYARG_4);
 const auto data = PySide::Signal::getEmitterData(signalInst);
-if (data.methodIndex == -1) {
-    PyErr_SetString(PyExc_RuntimeError, "QWizardPage::registerField(): Unable to retrieve signal emitter.");
-    return nullptr;
-}
+if (data.methodIndex == -1)
+    return PyErr_Format(PyExc_RuntimeError, "QWizardPage::registerField(): Unable to retrieve signal emitter.");
 const auto method = data.emitter->metaObject()->method(data.methodIndex);
 const QByteArray signature = QByteArrayLiteral("2") + method.methodSignature();
 %BEGIN_ALLOW_THREADS
@@ -773,6 +801,14 @@ const QByteArray signature = QByteArrayLiteral("2") + method.methodSignature();
 %END_ALLOW_THREADS
 // @snippet qwizardpage-registerfield
 
+// The constructor heuristics generate setting a parent-child relationship
+// when creating a QDialog with parent. This causes the dialog to leak
+// when it synchronous exec() is used instead of asynchronous show().
+// In that case, remove the parent-child relationship.
+// @snippet qdialog-exec-remove-parent-relation
+Shiboken::Object::removeParent(reinterpret_cast<SbkObject *>(%PYSELF));
+// @snippet qdialog-exec-remove-parent-relation
+
 /*********************************************************************
  * CONVERSIONS
  ********************************************************************/
diff --git a/sources/pyside6/PySide6/qiopipe.h b/sources/pyside6/PySide6/qiopipe.h
new file mode 100644 (file)
index 0000000..6a325f1
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QIOPIPE_H
+#define QIOPIPE_H
+
+#include <QtCore/qiodevicebase.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+namespace QtCoreHelper
+{
+
+class QIOPipePrivate;
+class QIOPipe : public QObject
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(QIOPipe)
+
+public:
+    QIOPipe(QObject *parent = nullptr);
+
+    bool open(QIODeviceBase::OpenMode mode);
+
+    QIODevice *end1() const;
+    QIODevice *end2() const;
+};
+
+} // namespace QtCoreHelper
+
+QT_END_NAMESPACE
+
+#endif // QIOPIPE_H
index 04764c9a485db5b14300fcfc36a0847b6657a4ec..871fa8284914111ff67fb6667005132d071f98e6 100644 (file)
@@ -21,6 +21,10 @@ Q_DECLARE_INTERFACE(QDesignerTaskMenuExtension, "org.qt-project.Qt.Designer.Task
 Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface")
 #endif
 
+struct _object; // PyObject
+
+QT_BEGIN_NAMESPACE
+
 // Extension implementations need to inherit QObject which cannot be done in Python.
 // Provide a base class (cf QPyTextObject).
 
@@ -56,8 +60,6 @@ public:
     explicit QPyDesignerTaskMenuExtension(QObject *parent = nullptr) : QObject(parent) {}
 };
 
-struct _object; // PyObject
-
 class QPyDesignerCustomWidgetCollection : public QDesignerCustomWidgetCollectionInterface
 {
 public:
@@ -77,4 +79,6 @@ private:
     QList<QDesignerCustomWidgetInterface *> m_customWidgets;
 };
 
+QT_END_NAMESPACE
+
 #endif // QPYDESIGNEREXTENSIONS_H
index 897ebfb5e1023617a7f25a3c928ebd797e7761e8..24dcdda754b401750e7a6335595a59b1bf6ff673 100644 (file)
@@ -11,6 +11,8 @@
 Q_DECLARE_INTERFACE(QQmlParserStatus, "org.qt-project.Qt.QQmlParserStatus")
 #endif
 
+QT_BEGIN_NAMESPACE
+
 // Inherit from QObject such that QQmlParserStatus can be found at
 // a fixed offset (RegisterType::parserStatusCast).
 class QPyQmlParserStatus : public QObject, public QQmlParserStatus
@@ -21,4 +23,6 @@ public:
     explicit QPyQmlParserStatus(QObject *parent = nullptr) : QObject(parent) {}
 };
 
+QT_END_NAMESPACE
+
 #endif // QPYQMLPARSERSTATUS_H
index 8e8fc24c1bb393ac8ae06573a0d1ef5fe39f8bb4..0b6a0b95ce453c355cc91bc5ddb64b3bc5620853 100644 (file)
@@ -10,6 +10,8 @@
 Q_DECLARE_INTERFACE(QQmlPropertyValueSource, "org.qt-project.Qt.QQmlPropertyValueSource")
 #endif
 
+QT_BEGIN_NAMESPACE
+
 // Inherit from QObject such that QQmlPropertyValueSource can be found at
 // a fixed offset (RegisterType::valueSourceCast).
 class QPyQmlPropertyValueSource : public QObject, public QQmlPropertyValueSource
@@ -20,4 +22,6 @@ public:
     explicit QPyQmlPropertyValueSource(QObject *parent = nullptr) : QObject(parent) {}
 };
 
+QT_END_NAMESPACE
+
 #endif // QPYQMLPROPERTYVALUESOURCE_H
index c667b2980dab95ca31b2a9fd0dabf7e25789d1b1..45bb0bd5281bd9665a5dd5b3663406e48dd90afc 100644 (file)
@@ -13,6 +13,7 @@
 Q_DECLARE_INTERFACE(QTextObjectInterface, "org.qt-project.Qt.QTextObjectInterface")
 #endif
 
+QT_BEGIN_NAMESPACE
 class QPyTextObject : public QObject, public QTextObjectInterface
 {
     Q_OBJECT
@@ -20,6 +21,8 @@ class QPyTextObject : public QObject, public QTextObjectInterface
 public:
     QPyTextObject(QObject *parent = nullptr) : QObject(parent) {}
 };
+QT_END_NAMESPACE
+
 #endif
 
 
index 3579d83c9a960204f08e5780b26e791d994f8b5b..589d0b295176579df8300fb7f5eb985a9571e23d 100644 (file)
@@ -9,6 +9,8 @@
 
 #include <memory>
 
+QT_BEGIN_NAMESPACE
+
 namespace QtCoreHelper {
 
     using MutexLocker = QT_PREPEND_NAMESPACE(QMutexLocker<QMutex>);
@@ -115,4 +117,6 @@ namespace QtCoreHelper {
 
 } // namespace QtCoreHelper
 
+QT_END_NAMESPACE
+
 #endif // QTCOREHELPER_H
index 6884900eefb7286a11710467c16733ae1ad208eb..8fee4492d0e594136b2381ab0afb32c36fc3b876 100644 (file)
@@ -6,8 +6,8 @@
 
 #include <sbkpython.h>
 
-#include <QtDataVisualization/QSurfaceDataProxy>
-#include <QtCore/QList>
+#include <QtDataVisualization/qsurfacedataproxy.h>
+#include <QtCore/qlist.h>
 
 namespace QtDataVisualizationHelper {
 
index b59d2db9c6226f89e196d3c30b63fd82c0aa7a74..7389ad81572d0c9e9cc6bf0a5924287173523d92 100644 (file)
@@ -8,6 +8,7 @@
 #include <QtDBus/qdbuspendingcall.h>
 #include <QtDBus/qdbusreply.h>
 
+QT_BEGIN_NAMESPACE
 namespace QtDBusHelper {
 
 // A Python-bindings friendly, non-template QDBusReply
@@ -56,4 +57,6 @@ inline QDBusReply::QDBusReply() = default;
 
 } // namespace QtDBusHelper
 
+QT_END_NAMESPACE
+
 #endif // QTDBUSHELPER_H
index 91ef818d387901ae7ca90a444bbbf3d47b3fe2bc..e488fc7d3139169d9c3033f7b9e46fbb10ee1148 100644 (file)
@@ -6,13 +6,13 @@
 
 #include <sbkpython.h>
 
-#include <QtGraphs/QSurfaceDataProxy>
-#include <QtCore/QList>
+#include <QtGraphs/qsurfacedataproxy.h>
+#include <QtCore/qlist.h>
 
 namespace QtGraphsHelper {
 
-QSurfaceDataArray *surfaceDataFromNp(double x, double deltaX, double z, double deltaZ,
-                                     PyObject *data);
+QSurfaceDataArray surfaceDataFromNp(double x, double deltaX, double z, double deltaZ,
+                                    PyObject *data);
 
 } // namespace QtGraphsHelper
 
index dfb7b994addd0eae2faa21773ac4a9ece6bcf821..e537cfefa9a98481b527015776c2ba8c64f5bf5b 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <QtGui/QGuiApplication>
 
+QT_BEGIN_NAMESPACE
 namespace QtGuiHelper {
 
     class QOverrideCursorGuard
@@ -29,5 +30,6 @@ namespace QtGuiHelper {
     };
 
 } // namespace QtGuiHelper
+QT_END_NAMESPACE
 
 #endif // QTGUIHELPER_H
index f215f2ff530a2650977614bd818fb024ef7f74ce..263dd3ed7fa60108923872ebefa0f222dc93aff1 100644 (file)
@@ -13,59 +13,6 @@ Functions that are to be called for
 
 Note that this fixing code is run after all initializations, but before the
 import is finished. But that is no problem since the module is passed in.
-
-PYSIDE-1735: This is also used now for missing other functions (overwriting __or__
-             in Qt.(Keyboard)Modifier).
 """
 
-import warnings
-from textwrap import dedent
-
-
-class PySideDeprecationWarningRemovedInQt6(Warning):
-    pass
-
-
-def constData(self):
-    cls = self.__class__
-    name = cls.__qualname__
-    warnings.warn(dedent(f"""
-        {name}.constData is unpythonic and will be removed in Qt For Python 6.0 .
-        Please use {name}.data instead."""), PySideDeprecationWarningRemovedInQt6, stacklevel=2)
-    return cls.data(self)
-
-
-# No longer needed but kept for reference.
-def _unused_fix_for_QtGui(QtGui):
-    for name, cls in QtGui.__dict__.items():
-        if name.startswith("QMatrix") and "data" in cls.__dict__:
-            cls.constData = constData
-
-# PYSIDE-1735: Fix for a special enum function
-def fix_for_QtCore(QtCore):
-    from enum import Flag
-    Qt = QtCore.Qt
-    flag_or = Flag.__or__
-
-    def func_or(self, other):
-        if isinstance(self, Flag) and isinstance(other, Flag):
-            # this is normal or-ing flags together
-            return Qt.KeyboardModifier(self.value | other.value)
-        return QtCore.QKeyCombination(self, other)
-
-    def func_add(self, other):
-        warnings.warn(dedent(f"""
-            The "+" operator is deprecated in Qt For Python 6.0 .
-            Please use "|" instead."""), PySideDeprecationWarningRemovedInQt6, stacklevel=2)
-        return func_or(self, other)
-
-    Qt.KeyboardModifier.__or__ = func_or
-    Qt.KeyboardModifier.__ror__ = func_or
-    Qt.Modifier.__or__ = func_or
-    Qt.Modifier.__ror__ = func_or
-    Qt.KeyboardModifier.__add__ = func_add
-    Qt.KeyboardModifier.__radd__ = func_add
-    Qt.Modifier.__add__ = func_add
-    Qt.Modifier.__radd__ = func_add
-
 # eof
index 5a2cf05ee9e99804dd8206cde54fd38f8ab9cf6b..92808e2a533e3992c46b612cd0ca26aad12c959e 100644 (file)
@@ -8,14 +8,14 @@ This script generates the .pyi files for all PySide modules.
 """
 
 import argparse
-import inspect
+import inspect  # noqa: F401
 import logging
 import os
 import sys
-import typing
+import typing  # noqa: F401
 
 from pathlib import Path
-from types import SimpleNamespace
+from types import SimpleNamespace  # noqa: F401
 
 # Can we use forward references?
 USE_PEP563 = sys.version_info[:2] >= (3, 7)
@@ -25,7 +25,7 @@ def generate_all_pyi(outpath, options):
     ps = os.pathsep
     if options.sys_path:
         # make sure to propagate the paths from sys_path to subprocesses
-        normpath = lambda x: os.fspath(Path(x).resolve())
+        normpath = lambda x: os.fspath(Path(x).resolve())  # noqa: E731
         sys_path = [normpath(_) for _ in options.sys_path]
         sys.path[0:0] = sys_path
         pypath = ps.join(sys_path)
@@ -63,15 +63,16 @@ if __name__ == "__main__":
     parser = argparse.ArgumentParser(
         description="This script generates the .pyi file for all PySide modules.")
     parser.add_argument("modules", nargs="+",
-        help="'all' or the names of modules to build (QtCore QtGui etc.)")
+                        help="'all' or the names of modules to build (QtCore QtGui etc.)")
     parser.add_argument("--quiet", action="store_true", help="Run quietly")
-    parser.add_argument("--check", action="store_true", help="Test the output if on Python 3")
     parser.add_argument("--outpath",
-        help="the output directory (default = binary location)")
+                        help="the output directory (default = binary location)")
     parser.add_argument("--sys-path", nargs="+",
-        help="a list of strings prepended to sys.path")
+                        help="a list of strings prepended to sys.path")
     parser.add_argument("--feature", nargs="+", choices=["snake_case", "true_property"], default=[],
-        help="""a list of feature names. Example: `--feature snake_case true_property`""")
+                        help="""a list of feature names. """
+                        """Example: `--feature snake_case true_property`. """
+                        """Currently not available for PyPy.""")
     options = parser.parse_args()
 
     qtest_env = os.environ.get("QTEST_ENVIRONMENT", "")
index bf6054a76436bccec166b0a35d4e4ff24a4bf5cd..1e434f9f68377b3a21eae2f051b64149b8831b12 100644 (file)
@@ -21,6 +21,21 @@ macro(unmake_path varname)
    string(REPLACE "${PATH_SEP}" ";" ${varname} "${ARGN}")
 endmacro()
 
+# Check for presence of QtOpenGL and modify module variables
+# accordingly
+macro(check_qt_opengl module include_var deps_var dropped_entries_var)
+    if (Qt${QT_MAJOR_VERSION}OpenGL_FOUND)
+        message(STATUS "Qt${QT_MAJOR_VERSION}${module}: Building with OpenGL")
+        list(APPEND ${include_var} ${Qt${QT_MAJOR_VERSION}OpenGL_INCLUDE_DIRS}
+                                   ${QtOpenGL_GEN_DIR})
+        list(APPEND ${deps_var} QtOpenGL)
+    else()
+        message(STATUS "Qt${QT_MAJOR_VERSION}${module}: Dropping OpenGL")
+        # This is a dummy entry creating a conditional typesystem keyword
+        list(APPEND ${dropped_entries_var} "QtOpenGL")
+    endif()
+endmacro()
+
 # set size optimization flags for pyside6
 macro(append_size_optimization_flags _module_name)
     if(NOT QFP_NO_OVERRIDE_OPTIMIZATION_FLAGS)
index c728e7c4396cf9b2ab0c0acde8296960b244a63f..23ceda6bd466af39a596ecf1db444fe5ac1e91d1 100644 (file)
@@ -103,6 +103,7 @@ macro(collect_optional_modules)
         Quick
         Quick3D
         QuickControls2
+        QuickTest
         QuickWidgets
         RemoteObjects
         Scxml
index bf55263ffd532edb0f6672416bd7a9c07f35501a..83583756f98f1e7e73114f9b4fe8956dd369e4dc 100644 (file)
@@ -32,7 +32,7 @@ if(NOT CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
         return()
     endif()
 else()
-    # We are building the docs as a standalone project, likely via setup.py build_rst_docs
+    # We are building the docs as a standalone project, likely via setup.py build_base_docs
     # command. Perform stricter sanity checks.
     if(NOT SPHINX_BUILD)
         message(FATAL_ERROR "sphinx-build command not found. Please set the SPHINX_BUILD variable.")
@@ -51,6 +51,10 @@ else()
 endif()
 
 set(DOC_DATA_DIR "${CMAKE_CURRENT_BINARY_DIR}/qdoc-output")
+# Directory for sphinx-generated files to build the HTML website. If changed,
+# update "build_scripts/main.py" in "PysideBaseDocs" class at line:
+# self.sphinx_src = self.out_dir / "base".
+set(DOC_BASE_DIR "base")
 
 set(ENV_INHERITANCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/inheritance.json")
 
@@ -60,7 +64,7 @@ set(TS_ROOT "${ROOT}/PySide6")
 file(REMOVE ${CMAKE_CURRENT_LIST_DIR}/pyside.qdocconf ${CMAKE_CURRENT_LIST_DIR}/pyside.qdocconf.in)
 
 # We need to find the interpreter when running this only
-# for a rst_build_docs case, and not a full doc build
+# for the 'build_base_docs' case, and not a full doc build
 if (NOT FULLDOCSBUILD)
     find_package(Python COMPONENTS Interpreter)
 endif()
@@ -82,7 +86,7 @@ set(TOOLS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../tools")
 if (FULLDOCSBUILD)
     # Fetch and transform the snippets from Qt
     set(SNIPPETS_TOOL "${TOOLS_DIR}/snippets_translate/main.py")
-    set(SNIPPETS_TARGET ${CMAKE_CURRENT_BINARY_DIR}/rst/codesnippets)
+    set(SNIPPETS_TARGET ${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}/codesnippets)
 
     # Note QT_SRC_DIR points to 'qtbase',
     # so we use the general SRC directory to copy all the other snippets
@@ -95,7 +99,7 @@ if (FULLDOCSBUILD)
 endif()
 
 # Generate example gallery
-set(EXAMPLE_TOOL_TARGET "${CMAKE_CURRENT_BINARY_DIR}/rst/examples")
+set(EXAMPLE_TOOL_TARGET "${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}/examples")
 set(EXAMPLE_TOOL_OPTIONS --target "${EXAMPLE_TOOL_TARGET}" --qt-src-dir "${QT_SRC_DIR}")
 if (QUIET_BUILD)
     list(APPEND EXAMPLE_TOOL_OPTIONS "-q")
@@ -190,7 +194,7 @@ endif()
 add_custom_target(apidoc
                   COMMAND ${CMAKE_COMMAND} -E env INHERITANCE_FILE=${ENV_INHERITANCE_FILE}
                           ${SHIBOKEN_PYTHON_INTERPRETER} ${SPHINX_BUILD} -b ${DOC_OUTPUT_FORMAT}
-                          -j 6 ${CMAKE_CURRENT_BINARY_DIR}/rst html
+                          -j 6 ${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR} html
                   COMMENT "Generating PySide htmls..."
                  )
 
@@ -224,14 +228,14 @@ else()
 endif()
 
 # create conf.py based on conf.py.in
-configure_file("conf.py.in" "rst/conf.py" @ONLY)
+configure_file("conf.py.in" "${DOC_BASE_DIR}/conf.py" @ONLY)
 
-set(CODE_SNIPPET_ROOT "${CMAKE_CURRENT_BINARY_DIR}/rst/codesnippets")
+set(CODE_SNIPPET_ROOT "${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}/codesnippets")
 
 if (FULLDOCSBUILD)
 shiboken_get_tool_shell_wrapper(shiboken tool_wrapper)
 
-add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/rst/PySide6/QtCore/index.rst"
+add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}/PySide6/QtCore/index.rst"
                    COMMAND
                        ${tool_wrapper}
                        $<TARGET_FILE:Shiboken6::shiboken6>
@@ -243,26 +247,26 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/rst/PySide6/QtCore/index.
                        --typesystem-paths="${QDOC_TYPESYSTEM_PATH}"
                        --library-source-dir=${QT_SRC_DIR}
                        --documentation-data-dir=${DOC_DATA_DIR}/webxml
-                       --output-directory=${CMAKE_CURRENT_BINARY_DIR}/rst
+                       --output-directory=${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}
                        --documentation-code-snippets-dir=${CODE_SNIPPET_ROOT}
                        --snippets-path-rewrite=${QT_ROOT_PATH}:${CODE_SNIPPET_ROOT}
-                       --documentation-extra-sections-dir=${CMAKE_CURRENT_BINARY_DIR}/rst/extras
-                       --additional-documentation=${CMAKE_CURRENT_BINARY_DIR}/rst/additionaldocs.lst
+                       --documentation-extra-sections-dir=${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}/extras
+                       --additional-documentation=${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}/additionaldocs.lst
                        --inheritance-file=${ENV_INHERITANCE_FILE}
                        ${global_typesystem}
                    WORKING_DIRECTORY ${${module}_SOURCE_DIR}
                    COMMENT "Running generator to generate documentation...")
 endif()
 
-add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/rst/extras"
-                   COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/rst
+add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}/extras"
+                   COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}
                    COMMENT "Copying docs...")
 
 add_custom_target("doc_copy"
-                  DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/rst/extras")
+                  DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}/extras")
 
 add_custom_target("docrsts"
-                  DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/rst/PySide6/QtCore/index.rst")
+                  DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}/PySide6/QtCore/index.rst")
 
 set(LIBEXEC_PATH "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_LIBEXECS}")
 add_custom_target("licensedocrsts"
@@ -270,7 +274,7 @@ add_custom_target("licensedocrsts"
             ${CMAKE_CURRENT_LIST_DIR}/qtattributionsscannertorst.py
             -l "${LIBEXEC_PATH}"
             ${CMAKE_CURRENT_LIST_DIR}/../../..
-            ${CMAKE_CURRENT_BINARY_DIR}/rst/licenses.rst
+            ${CMAKE_CURRENT_BINARY_DIR}/${DOC_BASE_DIR}/licenses.rst
     COMMENT "Creating 3rdparty license documentation..."
 )
 
index 90c0ee6701a088676255cc865ae963472843a7a1..326f6efccb6f2c4e5591c2bd4372e4e1a27b884c 100644 (file)
@@ -131,6 +131,11 @@ coroutine has finished, while ``quit_qapp`` determines if the
 QCoreApplication should be shut down after asyncio has finished. It is
 possible for asyncio to finish while the QCoreApplication is kept alive.
 
+An argument ``handle_sigint`` determines whether QtAsyncio should handle
+SIGINT (Ctrl+C) and shut down the event loop when it is received. The
+default is ``False``. Set this to ``True`` if you want QtAsyncio to take
+care of handling SIGINT instead of your program.
+
 Coroutines explained
 ^^^^^^^^^^^^^^^^^^^^
 
index 3e98c8ee84825a095314f26611d114719d47fde9..08c4646c62bd6fdf05aa071cf55a25741c42f143 100644 (file)
@@ -82,3 +82,19 @@ code.download:hover {
   text-decoration: none;
   padding: .375rem .75rem;
 }
+
+dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple):first-child > dt {
+  font-size: +2.25rem;
+  font-weight: 700;
+  color: #ff00dd;
+}
+
+.theme-toggle svg{
+  width: +1.25rem;
+  height: +2.25rem;
+}
+
+.sd-card-title code span {
+  font-size: +1rem;
+  color: var(--color-brand-primary);
+}
diff --git a/sources/pyside6/doc/_tags/android.rst b/sources/pyside6/doc/_tags/android.rst
new file mode 100644 (file)
index 0000000..08a30fc
--- /dev/null
@@ -0,0 +1,21 @@
+My tags: Android
+################
+
+.. toctree::
+    :maxdepth: 1
+    :caption: With this tag
+
+    ../examples/example_bluetooth_heartrate_game.rst
+    ../examples/example_bluetooth_lowenergyscanner.rst
+    ../examples/example_location_mapviewer.rst
+    ../examples/example_multimedia_audiooutput.rst
+    ../examples/example_multimedia_audiosource.rst
+    ../examples/example_multimedia_camera.rst
+    ../examples/example_qml_editingmodel.rst
+    ../examples/example_qml_usingmodel.rst
+    ../examples/example_quick_models_objectlistmodel.rst
+    ../examples/example_quick_models_stringlistmodel.rst
+    ../examples/example_quick_painteditem.rst
+    ../examples/example_quickcontrols_contactslist.rst
+    ../examples/example_quickcontrols_gallery.rst
+    ../examples/example_widgets_widgets_digitalclock.rst
diff --git a/sources/pyside6/doc/_tags/tagsindex.rst b/sources/pyside6/doc/_tags/tagsindex.rst
new file mode 100644 (file)
index 0000000..be29337
--- /dev/null
@@ -0,0 +1,12 @@
+:orphan:
+
+.. _tagoverview:
+
+Tags overview
+#############
+
+.. toctree::
+    :caption: Tags
+    :maxdepth: 1
+
+    Android (14) <android.rst>
index 33c88cfec40b0d36fc242348a33f78afbebe4dce..e74419d6acfcdfe1c2e8b86b1813e2bca756378d 100644 (file)
@@ -109,7 +109,7 @@ simplify the installation step::
 Complementary to the wheels, you will be able to download the sources
 as well.
 
-.. note:: Wheels installed this way will be detectable by `Qt Creator`_, which
+.. note:: Wheels installed this way will be detectable by `*Qt Creator*`_, which
    will offer you to install them for your current Python interpreter.
 
 Using account.qt.io
@@ -180,11 +180,11 @@ the wheels are::
 Qt Creator Integration
 ----------------------
 
-Qt Creator offers the option to create new |project| projects from the main
+*Qt Creator* offers the option to create new |project| projects from the main
 wizard.
 
 To execute the projects, make sure that the proper *Python Interpreter* is
-selected, so Qt Creator can use the commercial modules you just installed.
+selected, so *Qt Creator* can use the commercial modules you just installed.
 Go to *Edit -> Preferences* where you can find the *Python* option
 that will show the following:
 
@@ -197,7 +197,7 @@ select the main Python executable from your environment. This can be found on
 ``path_to_your_env/bin/python`` (macOS and Linux), or
 ``path_to_your_env\python.exe`` (Windows).
 
-As an alternative, you can launch Qt Creator from within the virtual
+As an alternative, you can launch *Qt Creator* from within the virtual
 environment, detecting your installation automatically.
 
 Migrating from other versions
index 45defe9e6a75f58e2a91441d80859f2ff71e4d04..e195d227fe8822180bc8aa3f587179df6c2b1131 100644 (file)
@@ -30,7 +30,8 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig',
     'sphinx.ext.coverage', 'sphinx.ext.intersphinx', 'sphinx.ext.todo',
     'sphinx.ext.graphviz', 'inheritance_diagram', 'pysideinclude',
     'sphinx.ext.viewcode',
-    'sphinx_design', 'sphinx_copybutton', 'myst_parser', 'sphinx_tags',]
+    'sphinx_design', 'sphinx_copybutton', 'myst_parser', 'sphinx_tags',
+    'sphinx_toolbox.decorators']
 
 myst_enable_extensions = [
     "amsmath",
@@ -227,7 +228,7 @@ intersphinx_mapping = {'shiboken6': ('shiboken6','@SHIBOKEN_INTERSPHINX_FILE@')}
 add_module_names = False
 
 # Skip some warnings when building the documentation with
-# 'build_rst_docs' due to the lack of qdoc generated files, in charge
+# 'build_base_docs' due to the lack of qdoc generated files, in charge
 # of sphinx modules (autodoc) and references.
 if @SKIP_SPHINX_WARNINGS@:
     suppress_warnings = ["autodoc", "autodoc.import_object", "ref.ref"]
index 78bd85bd62576306800bf4355ed79387794c9664..dda1d8b0db4e21dbcc774c9fafae0e13d76b91ff 100644 (file)
@@ -383,3 +383,59 @@ cannot be written in the shortcut form
 because there is no surrounding PySide class that provides the forgiving mode
 implementation. Typically, the needed changes are easily found because they often occur
 in an import statement.
+
+Permission API
+--------------
+
+The cross-platform permission APIs were introduced to Qt in version 6.5 which are currently relevant
+to platforms macOS, iOS, Android and WebAssembly. With this API, your Qt application can check and
+request permission for certain features like Camera, Microphone, Location, Bluetooth, Contacts,
+Calendar. More about permission API can be read in this `Blog post`_.
+
+When a PySide6 application that uses the permission API is run in interpreted mode, i.e.,
+``python <main_file>.py``, the code implementing the permission API *will not work*. The only way
+to make your PySide6 application using permission API work is to bundle the application. For Android,
+this means using the `pyside6-android-deploy`_ tool and for macOS, this means using the
+`pyside6-deploy`_ tool.
+
+When running in interpreted mode, you can skip over the permission check/request using the following
+*if* condition
+
+::
+
+    is_deployed = "__compiled__" in globals()
+    if not is_deployed and sys.platform == "darwin":
+        # code implementing permission check and request
+
+This can also be seen in the PySide6 `Camera example`_. * __compiled__ * is a Nuitka attribute to
+check if the application is run as a standalone application or run in interpreted mode with Python.
+
+Android
+~~~~~~~~
+
+For Android, `pyside6-android-deploy`_ takes care of identifying the necessary permissions needed by
+the application and adding those permissions to the *AndroidManifest.xml* using the
+*<uses-permission>* element.
+
+macOS
+~~~~~
+
+Since the Android platform does not automatically come bundled with a Python interpreter, it is
+evident that to make a PySide6 application run on Android you have to package the PySide6
+application. This is not the case for desktop platforms like macOS where a Python interpreter and
+its packages can be installed and run quite easily.
+
+The problem for macOS is that for the permission API to work you need a macOS bundle with an
+*Info.plist* file that lists all the permissions required using the *usage description* string for
+each permission used. When Python is run in interpreted mode, i.e., when you run Python, the Qt
+permission API fetches the *Info.plist* from the Python interpreter by default which does not
+contain the *usage description* strings for the permissions required. You can certainly modify the
+*Info.plist* of the Python framework installation to make the Qt permission API work when running
+a PySide6 application from the terminal. However, this is not recommended. Therefore, the only
+viable solution is to bundle the PySide6 application as a macOS application bundle using
+`pyside6-deploy`_. This macOS application bundle will have its own Info.plist file.
+
+.. _`Blog post`: https://www.qt.io/blog/permission-apis-in-qt-6.5
+.. _`Camera Example`: https://doc.qt.io/qtforpython-6/examples/example_multimedia_camera.html#camera-example
+.. _`pyside6-android-deploy`: https://doc.qt.io/qtforpython-6/gettingstarted/package_details.html#deployment
+.. _`pyside6-deploy`: https://doc.qt.io/qtforpython-6/gettingstarted/package_details.html#deployment
index 04203a53eba61d02dabcd953ab5eda74aa1d475a..4b6c7ffa9f71214b9dcbea0ede4dc1fa5ff7a66e 100644 (file)
@@ -7,6 +7,7 @@
     commercial/index.rst
     gettingstarted/index.rst
     api.rst
+    tools/index.rst
     tutorials/index.rst
     examples/index.rst
     videos.rst
diff --git a/sources/pyside6/doc/deployment/deployment-pyside6-android-deploy.rst b/sources/pyside6/doc/deployment/deployment-pyside6-android-deploy.rst
new file mode 100644 (file)
index 0000000..53944f6
--- /dev/null
@@ -0,0 +1,211 @@
+.. _pyside6-android-deploy:
+
+pyside6-android-deploy: the Android deployment tool for Qt for Python
+#####################################################################
+
+``pyside6-android-deploy`` is an easy-to-use tool for deploying PySide6 applications to different
+Android architectures, namely *arm64-v8a, x86_64, x86 and armeabi-v7a*. This tool works similarly to
+the ``pyside6-deploy`` tool and uses the same configuration file ``pysidedeploy.spec`` as
+``pyside6-deploy`` to configure the deployment process. Using the deployment configuration
+options either from the command line or from ``pysidedeploy.spec``, ``pyside6-android-deploy``
+configures the deployment to be initiated and invokes `buildozer`_, a tool used for packaging Python
+applications to Android.
+
+The final output is a `.apk` or a `.aab` file created within the project's source directory. The
+`mode` option specified under the :ref:`buildozer <buildozer_key>` key in ``pysidedeploy.spec``
+determines whether a `.apk` or a `.aab` is created.
+
+.. warning:: Currently, users are required to cross-compile Qt for Python to generate the wheels
+    required for a specific Android target architecture. This requirement will disappear when
+    there are official Qt for Python Android wheels (*in progress*). Because of this
+    requirement ``pyside6-android-deploy`` will be considered in **Technical Preview**.
+    Instructions on cross-compiling Qt for Python for Android can be found
+    :ref:`here <cross_compile_android>`.
+
+.. note:: ``pyside6-android-deploy`` only works on a Linux host at the moment. This constraint
+    is also because Qt for Python cross-compilation for Android currently only works on Linux
+    systems.
+
+How to use it?
+==============
+
+Like ``pyside6-deploy``, there are :ref:`two different ways <how_pysidedeploy>` with which
+you can deploy your PySide6 application using ``pyside6-android-deploy``. The only difference is
+that for ``pyside6-android-deploy`` to work, the main Python entry point file should be named
+``main.py``.
+
+.. _pysideandroiddeploy:
+
+pysidedeploy.spec
+=================
+
+Like ``pyside6-deploy``, you can use the ``pysidedeploy.spec`` file to control the various
+parameters of the deployment process. The file has multiple sections, with each section containing
+multiple keys (parameters being controlled) assigned to a value. The advantages of such a file are
+mentioned :ref:`here <pysidedeployspec_advantages>`. The benefit of using the same
+``pysidedeploy.spec`` for both ``pyside6-deploy`` and ``pyside6-android-deploy`` is that you can
+have one single file to control deployment to all platforms.
+
+The relevant parameters for ``pyside6-android-deploy`` are:
+
+**app**
+  * ``title``: The name of the application.
+  * ``project_dir``: Project directory. The general assumption made is that the project directory
+    is the parent directory of the main Python entry point file.
+  * ``input_file``: Path to the main Python entry point file. For ``pyside6-android-deploy`` this
+    file should be named `main.py`.
+  * ``project_file``: If it exists, this points to the path to the `Qt Creator Python Project File
+    .pyproject <https://doc.qt.io/qtforpython-6/faq/typesoffiles.html
+    #qt-creator-python-project-file-pyproject>`_ file. Such a file in the project directory ensures
+    that deployment does not consider unnecessary files when bundling the executable.
+  * ``exec_directory``: The directory where the final executable is generated.
+
+**python**
+  * ``python_path``: Path to the Python executable. It is recommended to run
+    ``pyside6-android-deploy`` from a virtual environment as certain Python packages will be
+    installed onto the Python environment. However, note to keep the created virtual environment
+    outside the project directory so that ``pyside6-android-deploy`` does not try to package it
+    as well.
+  * ``android_packages``: The Python packages installed into the Python environment for deployment
+    to work. By default, the Python packages `buildozer`_ and `cpython`_ are installed.
+
+.. _qt_key:
+
+**qt**
+  * ``modules``: Comma-separated list of all the Qt modules used by the application. Just like the
+    other configuration options in ``pysidedeploy.spec``, this option is also computed automatically
+    by ``pyside6-android-deploy``. However, if you want to explicitly include certain Qt modules,
+    the module names can be appended to this list without the `Qt` prefix.
+    e.g. Network instead of QtNetwork
+  * ``plugins``: This field is *not relevant* for ``pyside6-android-deploy`` and is only specific to
+    ``pyside6-deploy``. The plugins relevant for ``pyside6-android-deploy`` are specified through
+    the ``plugins`` option under the :ref:`android <android_key>` key.
+
+.. _android_key:
+
+**android**
+  * ``wheel_pyside``: Specifies the path to the PySide6 Android wheel for a specific target
+    architecture.
+  * ``wheel_pyside``: Specifies the path to the Shiboken6 Android wheel for a specific target
+    architecture.
+  * ``plugins``: Comma-separated list of all the Qt plugins used by the application. Just like the
+    other configuration options in ``pysidedeploy.spec``, this option is also computed automatically
+    by ``pyside6-android-deploy``. However, if you want to to explicitly include certain Qt plugins,
+    the plugin names can be appended to this list. To see all the plugins bundled with PySide6, see
+    the `plugins` folder in the ``site-packages`` on your Python where PySide6 is installed. The
+    plugin name corresponds to their folder name. This field can be confused with the ``plugins``
+    option under :ref:`qt <qt_key>` key. In the future, they will be merged into one single option.
+
+.. _buildozer_key:
+
+**buildozer**
+  * ``mode``: Specifies one of the two modes - `release` and `debug`, to run `buildozer`_. The
+    `release` mode creates an *aab* while the `debug` mode creates an apk. The default mode is
+    `debug`.
+  * ``recipe_dir``: Specifies the path to the directory containing `python-for-android`_ recipes.
+    This option is automatically computed by ``pyside6-android-deploy`` during deployment. Without
+    the :ref:`--keep-deployment-files <keep_deployment_files>` option of ``pyside6-android-deploy``,
+    the `recipe_dir` will point to a temporary directory that is deleted after the final Android
+    application package is created.
+  * ``jars_dir``: Specifies the path to the Qt Android `.jar` files that are relevant for
+    creating the Android application package. This option is automatically computed by
+    ``pyside6-android-deploy`` during deployment. Just like ``recipe_dir``, this field is also
+    *not relevant* unless used with the :ref:`--keep-deployment-files <keep_deployment_files>`
+    option of ``pyside6-android-deploy``.
+  * ``ndk_path``: Specifies the path to the Android NDK used for packaging the application.
+  * ``sdk_path``: Specifies the path to the Android SDK used for packaging the application.
+  * ``local_libs``: Specifies non-Qt plugins or other libraries compatible with the Android target
+    to be loaded by the Android runtime on startup.
+  * ``sdk_path``: Specifies the path to the Android SDK used for packaging the application.
+  * ``arch``: Specifies the target architecture's instruction set. This option take one of the four
+    values - *aarch64, armv7a, i686, x86_64*.
+
+Command Line Options
+====================
+
+Here are all the command line options of ``pyside6-android-deploy``:
+
+* **-c/--config-file**: This option is used to specify the path to ``pysidedeploy.spec`` explicitly.
+
+* **--init**: Used to only create the ``pysidedeploy.spec`` file.
+  Usage::
+
+    pyside6-android-deploy --init
+
+* **-v/--verbose**: Runs ``pyside6-android-deploy`` in verbose mode.
+
+* **--dry-run**: Displays the commands being run to produce the Android application package.
+
+.. _keep_deployment_files:
+
+* **--keep-deployment-files**: When this option is added, it retains the build folders created by
+  `buildozer`_ during the deployment process. This includes the folder storing the
+  `python-for-android`_ recipes, relevant `.jar` files and even the Android Gradle project for the
+  application.
+
+* **-f/--force**: When this option is used, it assumes ``yes`` to all prompts and runs
+  ``pyside6-android-deploy`` non-interactively. ``pyside6-android-deploy`` prompts the user to
+  create a Python virtual environment, if not already in one. With this option, the current Python
+  environment is used irrespective of whether the current Python environment is a virtual
+  environment or not.
+
+* **--name**: Application name.
+
+* **--wheel-pyside**:  Path to the PySide6 Android wheel for a specific target architecture.
+
+* **--wheel-shiboken**: Path to the Shiboken6 Android wheel for a specific target architecture.
+
+* **--ndk-path**:  Path to the Android NDK used for packaging the application.
+
+* **--sdk-path**: Path to the Android SDK used for packaging the application.
+
+* **--extra-ignore-dirs**: Comma-separated directory names inside the project directory. These
+  directories will be skipped when searching for Python files relevant to the project.
+
+* **--extra-modules**:  Comma-separated list of Qt modules to be added to the application,
+  in case they are not found automatically. The module name can either be specified
+  by omitting the prefix of Qt or including it eg: both Network and QtNetwork works.
+
+.. _cross_compile_android:
+
+Cross-compile Qt for Python wheels for Android
+==============================================
+
+The cross-compilation of Qt for Python wheel for a specific Android target architecture needs to be
+done only once per Qt version, irrespective of the number of applications you are deploying.
+Currently, cross-compiling Qt for Python wheels only works with a Linux host. Follow these steps
+to cross-compile Qt for Python Android wheels.
+
+#. `Download <qt_download>`_ and install Qt version for which you would like to create Qt for Python
+   wheels.
+
+#. Cloning the Qt for Python repository::
+
+    git clone https://code.qt.io/pyside/pyside-setup
+
+#. Check out the version that you want to build, for example 6.7. The version checked out has
+   to correspond to the Qt version downloaded in Step 1::
+
+    cd pyside-setup && git checkout 6.7
+
+#. Installing the dependencies::
+
+    pip install -r requirements.txt
+    pip install -r tools/cross_compile_android/requirements.txt
+
+#. Run the cross-compilation Python script.::
+
+    python tools/cross_compile_android/main.py --plat-name=aarch64 --qt-install-path=/opt/Qt/6.7.0
+    --auto-accept-license --skip-update
+
+   *--qt-install-path* refers to the path where Qt 6.7.0 is installed. *--auto-accept-license* and
+   *--skip-update* are required for downloading and installing Android NDK and SDK if not already
+   specified through command line options or if they don't already exist in the
+   ``pyside6-android-deploy`` cache. Use --help to see all the other available options::
+
+     python tools/cross_compile_android/main.py --help
+
+.. _`buildozer`: https://buildozer.readthedocs.io/en/latest/
+.. _`python-for-android`: https://python-for-android.readthedocs.io/en/latest/
+.. _`qt_download`: https://www.qt.io/download
+.. _`cpython`: https://pypi.org/project/Cython/
index f288dd32f65ad1396c113e30c3f67feb80abb55c..6a218fb3a4dc8b0d1197377d6bd820d32b938c8a 100644 (file)
@@ -7,8 +7,17 @@ pyside6-deploy: the deployment tool for Qt for Python
 platforms. It is a wrapper around `Nuitka <https://nuitka.net/>`_, a Python compiler that
 compiles your Python code to C code, and links with libpython to produce the final executable.
 
-The final executable produced has a ``.exe`` suffix on Windows. For Linux and macOS, they have a
-``.bin`` suffix.
+The final executable produced has a ``.exe`` suffix on Windows, ``.bin`` on Linux and ``.app`` on
+macOS.
+
+.. note:: Although using a virtual environment for Python is recommended for ``pyside6-deploy``, do
+    not add the virtual environment to the application directory you are trying to deploy.
+    ``pyside6-deploy`` will try to package this venv folder and will eventually fail.
+
+.. note:: The default version of Nuitka used with the tool is version ``2.3.2``. This can be
+    updated to a newer version by updating your ``pysidedeploy.spec`` file.
+
+.. _how_pysidedeploy:
 
 How to use it?
 ==============
@@ -62,8 +71,10 @@ parameters of the deployment process. The file has multiple sections, with each
 multiple keys (parameters being controlled) assigned to a value. The advantages of such a file are
 two folds:
 
+.. _pysidedeployspec_advantages:
+
 #. Using the command line, you can control the deployment parameters without specifying them each
-   time.. It is saved permanently in a file, and any subsequent runs much later in time
+   time. It is saved permanently in a file, and any subsequent runs much later in time
    would enable the user to be aware of their last deployment parameters.
 
 #. Since these parameters are saved into a file, they can be checked into version control. This
@@ -85,6 +96,9 @@ The relevant parameters for ``pyside6-deploy`` are:
     #qt-creator-python-project-file-pyproject>`_ file. Such a file makes sure that the deployment
     process never considers unnecessary files when bundling the executable.
   * ``exec_directory``: The directory where the final executable is generated.
+  * ``icon``: The icon used for the application. For Windows, the icon image should be of ``.ico``
+    format, for macOS it should be of ``.icns`` format, and for linux all standard image formats
+    are accepted.
 
 **python**
   * ``python_path``: Path to the Python executable. It is recommended to run the deployment
@@ -111,8 +125,28 @@ The relevant parameters for ``pyside6-deploy`` are:
     The reason why only the presence of the above 6 Qt modules is searched for is because they
     have the most size heavy binaries among all the Qt modules. With this, you can drastically
     reduce the size of your executables.
+  * ``modules``: Comma-separated list of all the Qt modules used by the application. Just like the
+    other configuration options in `pysidedeploy.spec`, this option is also computed automatically
+    by ``pyside6-deploy``. However, if the user wants to explicitly include certain Qt modules, the
+    module names can be appended to this list without the `Qt` prefix.
+    e.g. Network instead of QtNetwork
+  * ``plugins``: Comma-separated list of all the Qt plugins used by the application. Just like the
+    other configuration options in `pysidedeploy.spec`, this option is also computed automatically
+    by ``pyside6-deploy``. However, if the user wants to explicitly include certain Qt plugins,
+    the plugin names can be appended to this list. To see all the plugins bundled with PySide6,
+    see the `plugins` folder in the `site-packages` on your Python where PySide6 is installed. The
+    plugin name correspond to their folder name.
 
 **nuitka**
+  * ``macos.permissions``: Only relevant for macOS. This option lists the  permissions used by the
+    macOS application, as found in the ``Info.plist`` file of the macOS application bundle, using
+    the so-called UsageDescription strings. The permissions are normally automatically found by
+    ``pyside6-deploy``. However the user can also explicitly specify them using the format
+    `<UsageDescriptionKey>:<Short Description>`. For example, the Camera permission is specified
+    as::
+
+      NSCameraUsageDescription:CameraAccess
+
   * ``extra_args``: Any extra Nuitka arguments specified. It is specified as space-separated
     command line arguments i.e. just like how you would specify it when you use Nuitka through
     the command line. By default, it contains the following arguments::
@@ -142,9 +176,9 @@ Here are all the command line options of ``pyside6-deploy``:
     pyside6-deploy /path/to/main --init
 
 
-* **-v/--verbose**: Runs ``pyside6-deploy`` in verbose mode
+* **-v/--verbose**: Runs ``pyside6-deploy`` in verbose mode.
 
-* **--dry-run**: Displays the final Nuitka command being run
+* **--dry-run**: Displays the final Nuitka command being run.
 
 * **--keep-deployment-files**: When this option is added, it retains the build folders created by
    Nuitka during the deployment process.
@@ -153,3 +187,34 @@ Here are all the command line options of ``pyside6-deploy``:
   ``pyside6-deploy`` prompts the user to create a Python virtual environment, if not already in one.
   With this option, the current Python environment is used irrespective of whether the current
   Python environment is a virtual environment or not.
+
+* **--name**: Application name.
+
+* **--extra-ignore-dirs**: Comma-separated directory names inside the project directory. These
+  directories will be skipped when searching for Python files relevant to the project.
+
+* **--extra-modules**:  Comma-separated list of Qt modules to be added to the application,
+  in case they are not found automatically. The module name can either be specified
+  by omitting the prefix of Qt or including it eg: both Network and QtNetwork works.
+
+Considerations
+===============
+
+For deployment to work efficiently by bundling only the necessary plugins, the following utilities
+are required to be installed on the system:
+
+.. list-table::
+   :header-rows: 1
+
+   * - OS
+     - Dependencies
+     - Installation
+   * - Windows
+     - dumpbin
+     - Shipped with MSVC. Run `vcvarsall.bat` to add it to PATH
+   * - Linux
+     - readelf
+     - Available by default
+   * - macOS
+     - dyld_info
+     - Available by default from macOS 12 and upwards
index 6f4c2d44a1815e409b8502341e4fdb0cf95c34a9..36e677566a1b01b49e9b79019260c3742c872611 100644 (file)
@@ -17,8 +17,9 @@ Here are a few distribution options that you can use:
 
 If you are considering Option 3, then starting with 6.4, we ship a new tool called `pyside6-deploy`
 that deploys your PySide6 application to all desktop platforms - Windows, Linux, and macOS. To know
-more about how to use the tool see :ref:`pyside6-deploy`. Additionally, you can also use other
-popular deployment tools shown below:
+more about how to use the tool see :ref:`pyside6-deploy`. For Android deployment, see
+:ref:`pyside6-android-deploy`. Additionally, you can also use other popular deployment tools shown
+below:
 
 * `fbs`_
 * `PyInstaller`_
@@ -145,6 +146,7 @@ Here's a set of tutorials on how to use these tools:
     :maxdepth: 2
 
     deployment-pyside6-deploy.rst
+    deployment-pyside6-android-deploy.rst
     deployment-fbs.rst
     deployment-pyinstaller.rst
     deployment-cxfreeze.rst
index f8582f699101c3b8208a9731bb1ea2bd59177e23..aec81fb0fe94213f20bbaa1d23f50cdfc13b358b 100644 (file)
@@ -3,6 +3,9 @@
 Adapt to new Qt versions
 ========================
 
+Adapting to source changes
+--------------------------
+
 The dev branch of PySide is switched to a new Qt minor version
 after its API review is finished and the API is stable.
 
@@ -23,9 +26,9 @@ feature checks need to be added to ``CMakeList.txt`` (see for example
 The process consists of running a build and evaluating the log file.
 The script
 `shiboken2tasks.py <https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/scripts/shiboken2tasks.py>`_
-from the Qt Creator repository can be used to convert the shiboken warnings
+from the *Qt Creator* repository can be used to convert the shiboken warnings
 into a `task file <https://doc.qt.io/qtcreator/creator-task-lists.html>`_
-for display in the build issues pane of Qt Creator.
+for display in the build issues pane of *Qt Creator*.
 
 Warnings about new enumerations will be shown there; they should be added
 to type system file using a ``since`` attribute.
@@ -41,3 +44,11 @@ The Qt source code should be checked for new overloads
 The resolution needs to be decided for each individual case,
 mostly by removing old functions and using ``<declare-function>``
 to declare new API.
+
+Bumping the version
+-------------------
+
+To instruct ``COIN`` to use the next version of Qt, adapt the files
+``coin/dependencies.yaml`` and/or ``product_dependencies.yaml`` accordingly.
+Next, the wheel names should be changed by adapting
+``sources/shiboken6/.cmake.conf`` and ``sources/pyside6/.cmake.conf``.
index f75aa5489f1d04158adb2cfbb4c526c2c3f3dd8b..2eb962207e09251a29466c20cf1097f0a5f2f0f6 100644 (file)
@@ -18,7 +18,7 @@ Add bindings
 - Add it to ``build_scripts/wheel_files.py`` (plugins, translations).
 - Copy an existing module to ``sources/pyside6/PySide6/<name>``.
 - Adapt the ``typesystem.xml`` and ``CMakeList.txt`` (using for example
-  Qt Creator's case-preserving replace function).
+  *Qt Creator*'s case-preserving replace function).
 - Make sure the dependencies are correct.
 - Find the exported public classes, add them to the ``typesystem.xml`` file,
   checking whether they are ``value-type`` or ``object-type``. Add their enums
@@ -33,8 +33,8 @@ Add bindings
   typically hidden behind a progress message.
 - A convenient way of doing this is using
   ``qt-creator/scripts/shiboken2tasks.py`` from the
-  `Qt Creator repository <https://code.qt.io/cgit/qt-creator/qt-creator.git>`_
-  converting them to a ``.tasks`` file which can be loaded into Qt Creator's
+  `*Qt Creator* repository <https://code.qt.io/cgit/qt-creator/qt-creator.git>`_
+  converting them to a ``.tasks`` file which can be loaded into *Qt Creator*'s
   issue pane.
 - Link errors may manifest when ``generate_pyi`` imports the module trying
   to create signatures. They indicate a missing source file entry
index a894226c5eb4e001726cd4c4493cfdf69ed97394..732e6b915682e9ad1f8229c793c9ab7001434db1 100644 (file)
@@ -44,6 +44,8 @@ Add a Qt tool wrapper
 - Add the tool in ``sources/pyside-tools/pyside_tool.py``.
 - Add the tool in ``build_scripts/__init__.py`` to create the setuptools entry points
   i.e. this enable using the tool from the console as "pyside6-<tool_name>"
-- Add an entry to ``sources/pyside6/doc/gettingstarted/package_details.rst``.
+- Add an entry to ``sources/pyside6/doc/tools/index.rst`` and the detailed
+  documentation to ``sources/pyside6/doc/tools/<tool_name>.rst``.
 - Include the necessary Qt binaries explicitly on ``build_scripts/wheel_files.py``
-- Build with ``--standalone``, verify it is working.
+- Add the necessary files to ``build_scripts/wheel_files.py``.
+- Build with ``--standalone``, verify it is working. Also, check if the wheel bundles the tool.
index 79fc72190ec6b906f0ae7d74f0e3871dd78f0807..9788b539d687a2d2ed7cba9acd35e5560431116b 100644 (file)
@@ -24,6 +24,19 @@ Build on the command line
 
 - Consider using ``build_scripts/qp5_tool.py``.
 
+Build with address sanitizer (Linux)
+====================================
+
+ASAN needs to be told to not exit on memory leaks and its library
+needs to be pre-loaded. Assuming the library is found
+at ``/usr/lib/gcc/x86_64-linux-gnu/11``:
+
+.. code-block:: bash
+
+    export ASAN_OPTIONS=detect_leaks=0
+    export LD_PRELOAD=/usr/lib/gcc/x86_64-linux-gnu/11/libasan.so
+    python setup.py build [...] --sanitize-address
+
 De-Virtualize the Python Files
 ==============================
 
index aa080aa087f10499b26e5a1eb026a50b50719c06..75445e1fcfbef8c32ca0d9b04149dc240dbba88f 100644 (file)
@@ -1,11 +1,9 @@
 .. currentmodule:: PySide6.QtCore
-.. _ClassInfo:
+.. py:decorator:: ClassInfo
 
-ClassInfo
-*********
-
-This class is used to associate extra information to the class, which is available
-using QObject.metaObject(). Qt and PySide doesn't use this information.
+This decorator is used to associate extra information to the class, which is available
+using ``QObject.metaObject()``. This information is used by the
+*Qt D-Bus* and *Qt Qml* modules.
 
 The extra information takes the form of a dictionary with key and value in a literal string.
 
@@ -16,7 +14,7 @@ If the key needs to contain special characters (spaces, commas, '::', start with
 it is also possible to pass a python dictionary with arbitrary strings for both the key and
 value and enabling special characters in the key.
 
-.. note:: This Class is a implementation of Q_CLASSINFO macro.
+.. note:: This decorator is a implementation of the Q_CLASSINFO macro.
 
 
 Example
index 64567c4bcd51b94d9af4597b3b1d6fc2c147c5a9..9ed7de4278d904f1e41bbdcb41331d22fd3a2091 100644 (file)
@@ -1,8 +1,5 @@
 .. currentmodule:: PySide6.QtCore
-.. _Property:
-
-Property
-********
+.. py:class:: Property
 
 Detailed Description
 --------------------
index d42da91ab57db20d052885dc313c6a3259fcbfda..7ea35d8af322167ea7bd98081d98c54ba48826e5 100644 (file)
@@ -1,23 +1,19 @@
 .. currentmodule:: PySide6.QtCore
-.. _QEnum:
-
-QEnum/QFlag
-***********
-
-This class decorator is equivalent to the `Q_ENUM` macro from Qt.
-The decorator is used to register an Enum to the meta-object system,
-which is available via `QObject.staticMetaObject`.
-The enumerator must be in a QObject derived class to be registered.
+.. py:decorator:: QEnum
 
+This class decorator is equivalent to the `Q_ENUM` macro from Qt. The decorator
+is used to register a Python Enum derived class to the meta-object system,
+which is available via `QObject.staticMetaObject`. The enumerator must be in a
+QObject derived class to be registered.
 
 Example
 -------
 
 ::
 
-    from enum import Enum, Flag, auto
+    from enum import Enum, auto
 
-    from PySide6.QtCore import QEnum, QFlag, QObject
+    from PySide6.QtCore import QEnum, QObject
 
     class Demo(QObject):
 
@@ -25,67 +21,7 @@ Example
         class Orientation(Enum):
             North, East, South, West = range(4)
 
-        class Color(Flag):
-            RED = auto()
-            BLUE = auto()
-            GREEN = auto()
-            WHITE = RED | BLUE | GREEN
-
-        QFlag(Color)    # identical to @QFlag usage
-
-
-Caution:
---------
-
-QEnum registers a Python Enum derived class.
-QFlag treats a variation of the Python Enum, the Flag class.
-
-Please do not confuse that with the Qt QFlags concept. Python does
-not use that concept, it has its own class hierarchy, instead.
-For more details, see the `Python enum documentation <https://docs.python.org/3/library/enum.html>`_.
-
-
-Details about Qt Flags:
------------------------
-
-There are some small differences between Qt flags and Python flags.
-In Qt, we have for instance these declarations:
-
-::
-
-    enum    QtGui::RenderHint { Antialiasing, TextAntialiasing, SmoothPixmapTransform,
-                                HighQualityAntialiasing, NonCosmeticDefaultPen }
-    flags   QtGui::RenderHints
-
-The equivalent Python notation would look like this:
-
-::
-
-    @QFlag
-    class RenderHints(enum.Flag)
-        Antialiasing = auto()
-        TextAntialiasing = auto()
-        SmoothPixmapTransform = auto()
-        HighQualityAntialiasing = auto()
-        NonCosmeticDefaultPen = auto()
-
-
-As another example, the Qt::AlignmentFlag flag has 'AlignmentFlag' as the enum
-name, but 'Alignment' as the type name. Non flag enums have the same type and
-enum names.
-
-::
-
-    enum Qt::AlignmentFlag
-    flags Qt::Alignment
-
-The Python way to specify this would be
-
-::
-
-    @QFlag
-    class Alignment(enum.Flag):
-        ...
+See :deco:`QFlag` for registering Python Flag derived classes.
 
-Meanwhile we have converted all enums and flags to Python Enums (optional in ``PySide 6.3``,
-default in ``PySide 6.4``), see the :ref:`NewEnumSystem` section.
+Meanwhile all enums and flags have been converted to Python Enums
+(default since ``PySide 6.4``), see the :ref:`NewEnumSystem` section.
diff --git a/sources/pyside6/doc/extras/QtCore.QFlag.rst b/sources/pyside6/doc/extras/QtCore.QFlag.rst
new file mode 100644 (file)
index 0000000..dd4f028
--- /dev/null
@@ -0,0 +1,74 @@
+.. currentmodule:: PySide6.QtCore
+.. py:decorator:: QFlag
+
+QFlag handles a variation of the Python Enum, the Flag class.
+
+Please do not confuse that with the Qt QFlags concept. Python does
+not use that concept, it has its own class hierarchy, instead.
+For more details, see the `Python enum documentation <https://docs.python.org/3/library/enum.html>`_.
+
+Example
+-------
+
+::
+
+    from enum import Flag, auto
+
+    from PySide6.QtCore import QFlag, QObject
+
+    class Demo(QObject):
+
+        @QFlag
+        class Color(Flag):
+            RED = auto()
+            BLUE = auto()
+            GREEN = auto()
+            WHITE = RED | BLUE | GREEN
+
+
+Details about Qt Flags:
+-----------------------
+
+There are some small differences between Qt flags and Python flags.
+In Qt, we have for instance these declarations:
+
+::
+
+    enum    QtGui::RenderHint { Antialiasing, TextAntialiasing, SmoothPixmapTransform,
+                                HighQualityAntialiasing, NonCosmeticDefaultPen }
+    flags   QtGui::RenderHints
+
+The equivalent Python notation would look like this:
+
+::
+
+    @QFlag
+    class RenderHints(enum.Flag)
+        Antialiasing = auto()
+        TextAntialiasing = auto()
+        SmoothPixmapTransform = auto()
+        HighQualityAntialiasing = auto()
+        NonCosmeticDefaultPen = auto()
+
+
+As another example, the Qt::AlignmentFlag flag has 'AlignmentFlag' as the enum
+name, but 'Alignment' as the type name. Non flag enums have the same type and
+enum names.
+
+::
+
+    enum Qt::AlignmentFlag
+    flags Qt::Alignment
+
+The Python way to specify this would be
+
+::
+
+    @QFlag
+    class Alignment(enum.Flag):
+        ...
+
+See :deco:`QEnum` for registering Python Enum derived classes.
+
+Meanwhile all enums and flags have been converted to Python Enums
+(default since ``PySide 6.4``), see the :ref:`NewEnumSystem` section.
index 43dd4921627b36f4ead42df13b6bad56f2dc5b17..c83a76a8396bc597a9238ecc79801a8852c1a085 100644 (file)
@@ -1,8 +1,5 @@
 .. currentmodule:: PySide6.QtCore
-.. _Signal:
-
-Qt Signal
-*********
+.. py:class:: Signal
 
 Synopsis
 --------
index 06646e33c5f825e3e9fa9546fcb47c96793d7c58..98a1d465b546806625d825d9ce4c516c9ba2aaa7 100644 (file)
@@ -1,57 +1,42 @@
 .. currentmodule:: PySide6.QtCore
-.. _Slot:
+.. py:decorator:: Slot([type1 [, type2...]] [, name="" [, result=None, [tag=""]]])
 
-Qt Slots
-********
+   :param name: str
+   :param result: type
+   :param tag: str
 
-Detailed Description
---------------------
+``Slot`` takes a list of Python types of the arguments.
 
-    PySide6 adopt PyQt's new signal and slot syntax as-is. The PySide6
-    implementation is functionally compatible with the PyQt one, with the
-    exceptions listed below.
+The optional named argument ``name`` defines the slot name. If nothing is
+passed, the slot name will be the decorated function name.
 
-    PyQt's new signal and slot style utilizes method and decorator names
-    specific to their implementation. These will be generalized according to
-    the table below:
+The optional named argument ``result`` specifies the return type.
 
-    =======  =======================  =============
-    Module   PyQt factory function    PySide class
-    =======  =======================  =============
-    QtCore   pyqtSignal               Signal
-    QtCore   pyqtSlot                 Slot
-    =======  =======================  =============
+The optional named argument ``tag`` specifies a value to be returned
+by ``QMetaMethod.tag()``.
 
-    .. class:: PySide6.QtCore.Slot([type1 [, type2...]] [, name="" [, result=None, [tag=""]]])
+This implementation is functionally compatible with the PyQt one.
 
-            :param name: str
-            :param result: type
-            :param tag: str
+=======  ===========  ======
+Module   PyQt         PySide
+=======  ===========  ======
+QtCore   pyqtSignal   Signal
+QtCore   pyqtSlot     Slot
+=======  ===========  ======
 
-    ``Slot`` takes a list of Python types of the arguments.
-
-    The optional named argument ``name`` defines the slot name. If nothing is
-    passed, the slot name will be the decorated function name.
-
-    The optional named argument ``result`` specifies the return type.
-
-    The optional named argument ``tag`` specifies a value to be returned
-    by ``QMetaMethod.tag()``.
-
-    .. seealso:: :ref:`signals-and-slots`
+.. seealso:: :ref:`signals-and-slots`
 
 Q_INVOKABLE
 -----------
 
-    There is no equivalent of the Q_INVOKABLE macro of Qt
-    since PySide6 slots can actually have return values.
-    If you need to create a invokable method that returns some value,
-    declare it as a slot, e.g.:
-
-    ::
+There is no equivalent of the Q_INVOKABLE macro of Qt
+since PySide6 slots can actually have return values.
+If you need to create a invokable method that returns some value,
+declare it as a slot, e.g.:
 
-        class Foo(QObject):
+::
 
-            @Slot(float, result=int)
-            def getFloatReturnInt(self, f):
-                return int(f)
+    class Foo(QObject):
+        @Slot(float, result=int)
+        def getFloatReturnInt(self, f):
+            return int(f)
index 5280e5e2237e095cf0428873b4b902bd17e614dc..a3e5ef5115c4c25e2daad1fdac6a069c06417a00 100644 (file)
@@ -1,12 +1,9 @@
 .. currentmodule:: PySide6.QtDesigner
-.. _QPyDesignerContainerExtension:
-
-QPyDesignerContainerExtension
-*****************************
+.. py:class:: QPyDesignerContainerExtension
 
 QPyDesignerContainerExtension is the base class for implementing
 `QDesignerContainerExtension class`_
-for a Qt Designer custom widget plugin in Python.
+for a *Qt Widgets Designer* custom widget plugin in Python.
 It provides the required inheritance from **QObject**.
 
 .. _QDesignerContainerExtension class: https://doc.qt.io/qt-6/qdesignercontainerextension.html
index 71ef6cd69479b5740c9384154e039b26fbade665..615ca4eecc68ecfb477ec705c56a981ce4947653 100644 (file)
@@ -1,8 +1,5 @@
 .. currentmodule:: PySide6.QtDesigner
-.. _QPyDesignerCustomWidgetCollection:
-
-QPyDesignerCustomWidgetCollection
-*********************************
+.. py:class:: QPyDesignerCustomWidgetCollection
 
 Synopsis
 --------
@@ -29,7 +26,8 @@ The usage is explained in :ref:`designer_custom_widgets`.
 
 .. py:staticmethod:: QPyDesignerCustomWidgetCollection.registerCustomWidget(type[, xml=""[, tool_tip=""[, icon=""[, group=""[container=False]]]]])
 
-   Registers an instance of a Python-implemented QWidget by type with Qt Designer.
+   Registers an instance of a Python-implemented QWidget by type with
+   *Qt Widgets Designer*.
 
    The optional keyword arguments correspond to the getters of
    `QDesignerCustomWidgetInterface`_ :
@@ -47,7 +45,7 @@ The usage is explained in :ref:`designer_custom_widgets`.
 
     Adds a custom widget (implementation of
     `QDesignerCustomWidgetInterface`_)
-    with Qt Designer.
+    with *Qt Widgets Designer*.
 
    :param QDesignerCustomWidgetInterface custom_widget: Custom widget instance
 
index 997da1480ca233dc74b0d07e111fcc362614299f..ef23562219ab0ebf565749fb649108429e921797 100644 (file)
@@ -1,12 +1,9 @@
 .. currentmodule:: PySide6.QtDesigner
-.. _QPyDesignerMemberSheetExtension:
-
-QPyDesignerMemberSheetExtension
-*******************************
+.. py:class:: QPyDesignerMemberSheetExtension
 
 QPyDesignerMemberSheetExtension is the base class for implementing
 `QDesignerMemberSheetExtension class`_
-for a Qt Designer custom widget plugin in Python.
+for a *Qt Widgets Designer* custom widget plugin in Python.
 It provides the required inheritance from **QObject**.
 
 .. _QDesignerMemberSheetExtension class: https://doc.qt.io/qt-6/qdesignermembersheetextension.html
index 84d19c544024c6a3503bd207940dda239328e3d3..e5e13122d25ecf4197557d13e4dc4b151c8bc6ff 100644 (file)
@@ -1,12 +1,9 @@
 .. currentmodule:: PySide6.QtDesigner
-.. _QPyDesignerTaskMenuExtension:
-
-QPyDesignerTaskMenuExtension
-****************************
+.. py:class:: QPyDesignerTaskMenuExtension
 
 QPyDesignerTaskMenuExtension is the base class for implementing
 `QDesignerTaskMenuExtension class`_
-for a Qt Designer custom widget plugin in Python.
+for a *Qt Widgets Designer* custom widget plugin in Python.
 It provides the required inheritance from **QObject**.
 
 .. _QDesignerTaskMenuExtension class: https://doc.qt.io/qt-6/qdesignertaskmenuextension.html
index c232128ddf1d814a605a65672081ea855237ce48..844f25b7b5cb68c3fe3ac749a898681fe40c8540 100644 (file)
@@ -1,5 +1,6 @@
-Provides classes to create your own custom widget plugins for Qt Designer and
-classes to access Qt Designer components.
+Provides classes to create your own custom widget plugins for
+*Qt Widgets Designer* and classes to access *Qt Widgets Designer*
+components.
 
 In addition, the :class:`QFormBuilder<PySide6.QtDesigner.QFormBuilder>` class
 provides the possibility of constructing user interfaces from UI files at
diff --git a/sources/pyside6/doc/extras/QtQml.ListProperty.rst b/sources/pyside6/doc/extras/QtQml.ListProperty.rst
new file mode 100644 (file)
index 0000000..eaa580c
--- /dev/null
@@ -0,0 +1,24 @@
+.. currentmodule:: PySide6.QtQml
+.. py:class:: ListProperty
+
+    The ``ListProperty`` class allows applications to expose list-like properties of
+    :class:`~PySide6.QtCore.QObject`-derived classes to QML.
+    The usage is shown in the :ref:`qml-object-and-list-property-types-example`
+    and the :ref:`qml-chapter5-listproperties` example.
+
+    .. py:method:: __init__(type, append, count=None, at=None, clear=None, removeLast=None, doc="", notify=None, designable=True, scriptable=True, stored=True, user=False, constant=False, final=False)
+
+      :param type type: Element type
+      :param callable append: A function to append an item
+      :param callable count: A function returning the list count
+      :param callable at: A function returning the item at an index
+      :param callable clear: A function to clear the list
+      :param removeLast: A function to remove the last item
+      :param str doc: Doc string
+      :param Signal notify: A signal emitted when a change occurs
+      :param bool designable: Not used in QML
+      :param bool scriptable: Not used in QML
+      :param bool stored: Whether the property is stored
+      :param bool user: Not used in QML
+      :param bool constant: Whether the property is constant
+      :param bool final: Whether the property is final
index f027885afa603b6e7055ba7fcdafad8f07ee9685..10dde6b9ab178e98fbea95413da48f8fedeab883 100644 (file)
@@ -1,8 +1,5 @@
 .. currentmodule:: PySide6.QtQml
-.. _QPyQmlParserStatus:
-
-QPyQmlParserStatus
-******************
+.. py:class:: QPyQmlParserStatus
 
 QPyQmlParserStatus is the base class for implementing
 `QQmlParserStatus class`_ .
index fea238827b2c12ba569b546067e815dadfa63a0b..bf7f8e98f67718806a70c09ae8a4004ad924a982 100644 (file)
@@ -1,8 +1,5 @@
 .. currentmodule:: PySide6.QtQml
-.. _QPyQmlPropertyValueSource:
-
-QPyQmlPropertyValueSource
-*************************
+.. py:class:: QPyQmlPropertyValueSource
 
 QPyQmlPropertyValueSource is the base class for implementing
 `QQmlPropertyValueSource class`_ .
index a805b0763210b7f65f2b3d38a32da7fe0d7eef32..44aa0ea21a46c8cf81fe38a706ed476e620f55d1 100644 (file)
@@ -1,22 +1,17 @@
 .. currentmodule:: PySide6.QtQml
-.. _QmlAnonymous:
-
-QmlAnonymous
-************
-
 .. py:decorator:: QmlAnonymous
 
-   Declares the enclosing type to be available, but anonymous in QML. The type
-   cannot be created or used to declare properties in QML, but when passed from
-   C++, it is recognized. In QML, you can use properties of this type if they
-   are declared in C++.
+Declares the enclosing type to be available, but anonymous in QML. The type
+cannot be created or used to declare properties in QML, but when passed from
+C++, it is recognized. In QML, you can use properties of this type if they
+are declared in C++.
 
-   .. code-block:: python
+.. code-block:: python
 
-      QML_IMPORT_NAME = "com.library.name"
-      QML_IMPORT_MAJOR_VERSION = 1
-      QML_IMPORT_MINOR_VERSION = 0 # Optional
+    QML_IMPORT_NAME = "com.library.name"
+    QML_IMPORT_MAJOR_VERSION = 1
+    QML_IMPORT_MINOR_VERSION = 0 # Optional
 
-      @QmlAnonymous
-      class ClassForQml(QObject):
-          # ...
+    @QmlAnonymous
+    class ClassForQml(QObject):
+        # ...
index e3fefb6b28a95e1ac7857865338d015d5659f9a0..4331b03f9590401ea93102e209c2852cfe3e9235 100644 (file)
@@ -1,9 +1,4 @@
 .. currentmodule:: PySide6.QtQml
-.. _QmlAttached:
-
-QmlAttached
-***********
-
 .. py:decorator:: QmlAttached
 
 This decorator declares that the enclosing type attaches the type passed as
index 2746fbc0b5c0e966f214b7b1915e5f7f1d3abcba..66397b2d9be20f71de2e177abf9cc0b42ce22a39 100644 (file)
@@ -1,30 +1,25 @@
 .. currentmodule:: PySide6.QtQml
-.. _QmlElement:
-
-QmlElement
-**********
-
 .. py:decorator:: QmlElement
 
-   This decorator registers a class it is attached to for use in QML, using
-   global variables to specify the import name and version.
+This decorator registers a class it is attached to for use in QML, using
+global variables to specify the import name and version.
 
-   .. code-block:: python
+.. code-block:: python
 
-      QML_IMPORT_NAME = "com.library.name"
-      QML_IMPORT_MAJOR_VERSION = 1
-      QML_IMPORT_MINOR_VERSION = 0 # Optional
+    QML_IMPORT_NAME = "com.library.name"
+    QML_IMPORT_MAJOR_VERSION = 1
+    QML_IMPORT_MINOR_VERSION = 0 # Optional
 
-      @QmlElement
-      class ClassForQml(QObject):
-          # ...
+    @QmlElement
+    class ClassForQml(QObject):
+        # ...
 
-   Afterwards the class may be used in QML:
+Afterwards the class may be used in QML:
 
-   .. code-block:: python
+.. code-block:: python
 
-      import com.library.name 1.0
+    import com.library.name 1.0
 
-      ClassForQml {
-         // ...
-      }
+    ClassForQml {
+       // ...
+    }
index f9ed5a1066fc8d0d0f855fc10ae2ec46c1263ef4..af113a9c80479c0aa4f0f92464a2a38c9657ffb1 100644 (file)
@@ -1,9 +1,4 @@
 .. currentmodule:: PySide6.QtQml
-.. _QmlExtended:
-
-QmlExtended
-***********
-
 .. py:decorator:: QmlExtended
 
 Declares that the enclosing type uses the type passed as an extension to
index c58be3cb966660eabf9429bf8f0780709a766c25..90b821e9b8bf0aa4645b86079729ff74c7d3ef01 100644 (file)
@@ -1,33 +1,28 @@
 .. currentmodule:: PySide6.QtQml
-.. _QmlForeign:
-
-QmlForeign
-**********
-
 .. py:decorator:: QmlForeign
 
-   This decorator can be used to change the type that is created by QML.
+This decorator can be used to change the type that is created by QML.
 
-   This is useful for registering types that cannot be amended by adding the
-   QmlElement decorator, for example because they belong to 3rdparty libraries.
+This is useful for registering types that cannot be amended by adding the
+QmlElement decorator, for example because they belong to 3rdparty libraries.
 
-   .. code-block:: python
+.. code-block:: python
 
-      QML_IMPORT_NAME = "com.library.name"
-      QML_IMPORT_MAJOR_VERSION = 1
-      QML_IMPORT_MINOR_VERSION = 0 # Optional
+    QML_IMPORT_NAME = "com.library.name"
+    QML_IMPORT_MAJOR_VERSION = 1
+    QML_IMPORT_MINOR_VERSION = 0 # Optional
 
-      @QmlNamedElement("QWidget")
-      @QmlForeign(QWidget)
-      class ForeignWidgetHelperClass(QObject):
+    @QmlNamedElement("QWidget")
+    @QmlForeign(QWidget)
+    class ForeignWidgetHelperClass(QObject):
           ...
 
-   Afterwards the class may be used in QML:
+Afterwards the class may be used in QML:
 
-   .. code-block:: javascript
+.. code-block:: javascript
 
-      import com.library.name 1.0
+    import com.library.name 1.0
 
-      QWidget {
-         // ...
-      }
+    QWidget {
+        // ...
+    }
index d603e2e83578a9b02b42cd8b85fc91ea604d6e12..79eb9d7adfe188a7e0b677495e4a76e4256537ae 100644 (file)
@@ -1,31 +1,26 @@
 .. currentmodule:: PySide6.QtQml
-.. _QmlNamedElement:
-
-QmlNamedElement
-***************
-
 .. py:decorator:: QmlNamedElement
 
-   This decorator registers a class it is attached to for use in QML under
-   a name different from the class name, using global variables to specify
-   the import name and version.
+This decorator registers a class it is attached to for use in QML under
+a name different from the class name, using global variables to specify
+the import name and version.
 
-   .. code-block:: python
+.. code-block:: python
 
-      QML_IMPORT_NAME = "com.library.name"
-      QML_IMPORT_MAJOR_VERSION = 1
-      QML_IMPORT_MINOR_VERSION = 0 # Optional
+    QML_IMPORT_NAME = "com.library.name"
+    QML_IMPORT_MAJOR_VERSION = 1
+    QML_IMPORT_MINOR_VERSION = 0 # Optional
 
-      @QmlNamedElement("ClassForQml")
-      class ClassWithSomeName(QObject):
+    @QmlNamedElement("ClassForQml")
+    class ClassWithSomeName(QObject):
           ...
 
-   Afterwards the class may be used in QML:
+Afterwards the class may be used in QML:
 
-   .. code-block:: javascript
+.. code-block:: javascript
 
-      import com.library.name 1.0
+    import com.library.name 1.0
 
-      ClassForQml {
-         // ...
-      }
+    ClassForQml {
+       // ...
+    }
index a2430389b99610e7408e5024bc05984fa58c0186..402c18d55deaf1ddc47100658aa90b95fafe4ad5 100644 (file)
@@ -1,13 +1,8 @@
 .. currentmodule:: PySide6.QtQml
-.. _QmlSingleton:
-
-QmlSingleton decorator
-**********************
-
 .. py:decorator:: QmlSingleton
 
 Declares the decorated type to be a singleton in QML. This only takes effect if
-the type is a Q_OBJECT and is available in QML (by having a QmlElement decorator).
+the type is a QObject and is available in QML (by having a QmlElement decorator).
 The QQmlEngine will try to create a singleton instance using the type's default
 constructor.
 
@@ -22,4 +17,17 @@ constructor.
     class ClassForQml(QObject):
         ...
 
+It is also possible to use a static ``create()`` method which receives
+the engine as a parameter:
+
+.. code-block:: python
+
+    @QmlElement
+    @QmlSingleton
+    class ClassForQml(QObject):
+
+        @staticmethod
+        def create(engine):
+            ...
+
 .. note:: The order of the decorators matters; ``QmlSingleton`` needs to be preceded by ``QmlElement``.
index 46c7c49decdd21e84be859e1bda6ed96ae3871c8..b7a28801fbdf02727e7a1864013f1d5032e7480e 100644 (file)
@@ -1,9 +1,4 @@
 .. currentmodule:: PySide6.QtQml
-.. _QmlUncreatable:
-
-QmlUncreatable
-**************
-
 .. py:decorator:: QmlUncreatable
 
 Declares that the decorated type shall not be creatable from QML. This takes
diff --git a/sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst b/sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst
deleted file mode 100644 (file)
index 19d5989..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-.. currentmodule:: PySide6.QtQml
-.. _qmlRegisterSingletonInstance:
-
-qmlRegisterSingletonInstance
-****************************
-
-.. py:function:: qmlRegisterSingletonInstance(pytype: type,\
-                                              uri: str,\
-                                              versionMajor: int,\
-                                              versionMinor: int,\
-                                              typeName: str,\
-                                              instanceObject: object) -> int
-
-   :param type pytype: Python class
-   :param str uri: uri to use while importing the component in QML
-   :param int versionMajor: major version
-   :param int versionMinor: minor version
-   :param str typeName: name exposed to QML
-   :param object instanceObject: singleton object to be registered
-   :return: int (the QML type id)
-
-   This function registers a singleton Python object *instanceObject*, with a particular *uri* and
-   *typeName*. Its version is a combination of *versionMajor* and *versionMinor*.
-
-   Use this function to register an object of the given type *pytype* as a singleton type.
diff --git a/sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonType.rst b/sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonType.rst
deleted file mode 100644 (file)
index 32231a3..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-.. currentmodule:: PySide6.QtQml
-.. _qmlRegisterSingletonType:
-
-qmlRegisterSingletonType
-************************
-
-.. py:function:: qmlRegisterSingletonType(pytype: type, uri: str, versionMajor: int, versionMinor: int, typeName: str) -> int
-
-   :param type pytype: Python class
-   :param str uri: uri to use while importing the component in QML
-   :param int versionMajor: major version
-   :param int versionMinor: minor version
-   :param str typeName: name exposed to QML
-   :return: int (the QML type id)
-
-   This function registers a Python type as a singleton in the QML system.
-
-   Alternatively, the :ref:`QmlSingleton` decorator can be used.
-
-.. py:function:: qmlRegisterSingletonType(pytype: type, uri: str, versionMajor: int, versionMinor: int, typeName: str, callback: object) -> int
-
-   :param type pytype: Python class
-   :param str uri: uri to use while importing the component in QML
-   :param int versionMajor: major version
-   :param int versionMinor: minor version
-   :param str typeName: name exposed to QML
-   :param object callback: Python callable (to handle Python type)
-   :return: int (the QML type id)
-
-   This function registers a Python type as a singleton in the QML system using
-   the provided callback (which gets a QQmlEngine as a parameter) to generate
-   the singleton.
-
-
-.. py:function:: qmlRegisterSingletonType(uri: str, versionMajor: int, versionMinor: int, typeName: str, callback: object) -> int
-
-   :param str uri: uri to use while importing the component in QML
-   :param int versionMajor: major version
-   :param int versionMinor: minor version
-   :param str typeName: name exposed to QML
-   :param object callback: Python callable (to handle QJSValue)
-   :return: int (the QML type id)
-
-   This function registers a QJSValue as a singleton in the QML system using
-   the provided callback (which gets a QQmlEngine as a parameter) to
-   generate the singleton.
diff --git a/sources/pyside6/doc/extras/QtQml.qmlRegisterType.rst b/sources/pyside6/doc/extras/QtQml.qmlRegisterType.rst
deleted file mode 100644 (file)
index 079e15b..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-.. currentmodule:: PySide6.QtQml
-.. _qmlRegisterType:
-
-qmlRegisterType
-***************
-
-.. py:function:: qmlRegisterType(pytype: type, uri: str, versionMajor: int, versionMinor: int, qmlName: str) -> int
-
-   :param type pytype: Python class
-   :param str uri: uri to use while importing the component in QML
-   :param int versionMajor: major version
-   :param int versionMinor: minor version
-   :param str qmlName: name exposed to QML
-   :return: int (the QML type id)
-
-   This function registers the Python *type* in the QML system with the
-   name *qmlName*, in the library imported from *uri* having the
-   version number composed from *versionMajor* and *versionMinor*.
-
-   For example, this registers a Python class 'MySliderItem' as a QML
-   type named 'Slider' for version '1.0' of a module called
-   'com.mycompany.qmlcomponents':
-
-   ::
-
-       qmlRegisterType(MySliderItem, "com.mycompany.qmlcomponents", 1, 0, "Slider")
-
-   Once this is registered, the type can be used in QML by importing
-   the specified module name and version number:
-
-   ::
-
-       import com.mycompany.qmlcomponents 1.0
-
-       Slider { ... }
-
-   Note that it's perfectly reasonable for a library to register types
-   to older versions than the actual version of the library.
-   Indeed, it is normal for the new library to allow QML written to
-   previous versions to continue to work, even if more advanced
-   versions of some of its types are available.
diff --git a/sources/pyside6/doc/extras/QtQml.qmlRegisterUncreatableType.rst b/sources/pyside6/doc/extras/QtQml.qmlRegisterUncreatableType.rst
deleted file mode 100644 (file)
index be25f5f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-.. currentmodule:: PySide6.QtQml
-.. _qmlRegisterUncreatableType:
-
-
-qmlRegisterUncreatableType
-**************************
-
-
-.. py:function:: qmlRegisterUncreatableType(pytype: type, uri: str, versionMajor: int, versionMinor: int, qmlName: str, noCreationReason: str) -> int
-
-
-   :param type pytype: Python class
-   :param str uri: uri to use while importing the component in QML
-   :param int versionMajor: major version
-   :param int versionMinor: minor version
-   :param str qmlName: name exposed to QML
-   :param str noCreationReason: Error message shown when trying to create the QML type
-   :return: int (the QML type id)
-
-   This function registers the Python *type* in the QML system as an uncreatable type with the
-   name *qmlName*, in the library imported from *uri* having the
-   version number composed from *versionMajor* and *versionMinor*,
-   showing *noCreationReason* as an error message when creating the type is attempted.
-
-   For example, this registers a Python class 'MySliderItem' as a QML
-   type named 'Slider' for version '1.0' of a module called
-   'com.mycompany.qmlcomponents':
-
-   ::
-       qmlRegisterUncreatableType(MySliderItem, "com.mycompany.qmlcomponents", 1, 0, "Slider", "Slider cannot be created.")
-
-   Note that it's perfectly reasonable for a library to register types
-   to older versions than the actual version of the library.
-   Indeed, it is normal for the new library to allow QML written to
-   previous versions to continue to work, even if more advanced
-   versions of some of its types are available.
-
-   Alternatively, the :ref:`QmlUncreatable` decorator can be used.
diff --git a/sources/pyside6/doc/extras/QtQuickTest.rst b/sources/pyside6/doc/extras/QtQuickTest.rst
new file mode 100644 (file)
index 0000000..52f1359
--- /dev/null
@@ -0,0 +1,58 @@
+ Qt Quick Test is a unit test framework for QML applications. Test cases are
+ written as JavaScript functions within a QML TestCase type:
+
+.. code-block:: JavaScript
+
+    import QtQuick
+    import QtTest
+
+    TestCase {
+        name: "MathTests"
+
+        function test_math() {
+            compare(2 + 2, 4, "2 + 2 = 4")
+        }
+
+        function test_fail() {
+            compare(2 + 2, 5, "2 + 2 = 5")
+        }
+    }
+
+Functions whose names start with ``test_`` are treated as test cases to be
+executed.
+
+QML API
+^^^^^^^
+
+The `QML types <https://doc.qt.io/qt-6/qttest-qmlmodule.html>`_
+in Qt Quick Test are available through the ``QtTest`` import.
+To use the types, add the following import statement to your ``.qml`` file:
+
+.. code-block:: JavaScript
+
+    import QtTest
+
+Running Tests
+^^^^^^^^^^^^^
+
+Test cases are launched by a harness that consists of the following code:
+
+.. code-block:: Python
+
+    import sys
+    from PySide6.QtQuickTest import QUICK_TEST_MAIN
+
+    QUICK_TEST_MAIN("example", sys.argv)
+
+Where "example" is the identifier to use to uniquely identify this set of
+tests.
+
+Test execution can be controlled by a number of command line options (pass
+``-h`` for help).
+
+Executing Code Before QML Tests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To execute code before any of the QML tests are run, the
+:py:func:`QUICK_TEST_MAIN_WITH_SETUP` function can be used. This can be useful
+for setting context properties on the QML engine, amongst other things.
diff --git a/sources/pyside6/doc/extras/QtUiTools.loadUiType.rst b/sources/pyside6/doc/extras/QtUiTools.loadUiType.rst
deleted file mode 100644 (file)
index 48879d2..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-.. currentmodule:: PySide6.QtUiTools
-
-loadUiType
-***********
-
-.. py:function:: loadUiType(uifile: str) -> tuple(object, object)
-
-   :param str uifile: The name of the `.ui` file
-   :return: tuple(object, object)
-
-    This function generates and loads a `.ui` file at runtime, and it returns
-    a `tuple` containing the reference to the Python class, and the base class.
-
-    We recommend not to use this approach as the workflow should be to generate a Python file
-    from the `.ui` file, and then import and load it to use it, but we do understand that
-    there are some corner cases when such functionality is required.
-
-    The internal process relies on `uic` being in the PATH.
-    The `pyside6-uic` wrapper uses a shipped `uic` that is located in the
-    `site-packages/PySide6/uic`, so PATH needs to be updated to use that if there
-    is no `uic` in the system.
-
-    A simple use case is::
-
-        from PySide6.QtUiTools import loadUiType
-
-        generated_class, base_class = loadUiType("themewidget.ui")
-        # the values will be:
-        #  (<class '__main__.Ui_ThemeWidgetForm'>, <class 'PySide6.QtWidgets.QWidget'>)
-
-        widget = base_class()
-        form = generated_class()
-        form.setupUi(widget)
-        # form.a_widget_member.a_method_of_member()
-        widget.show()
index c4873b43d88b6f8ac6ace4cc70f6be2ea3110b02..e83aa03570be0d8ec057d95cb90b6b0a5dee635b 100644 (file)
@@ -1,4 +1,4 @@
-Qt Designer forms are processed at run-time to produce
+*Qt Widgets Designer* forms are processed at run-time to produce
 dynamically-generated user interfaces. In order to generate a form at
 run-time, a resource file containing a UI file is needed.
 
index 8c91d3e31a3e10f3ba284bc513b53f5ea3e0d92f..784421aac4f70784b3feb01db33dda7ede8aaadf 100644 (file)
@@ -52,7 +52,7 @@ widget reports its size requirements to the layout through the
 :meth:`sizePolicy<PySide6.QtWidgets.QWidget.sizePolicy>` properties,
 and the layout distributes the available space accordingly.
 
-:ref:`Qt Designer<using_ui_files>` is a powerful tool for interactively
+:ref:`Qt Widgets Designer<using_ui_files>` is a powerful tool for interactively
 creating and arranging widgets in layouts.
 
 Model/View Classes
index d3bd4512d2ff4ee89a84a0c37d6c4a488c6954c1..3155b24fc43da5b5b21125413c5f36366ffdb576 100644 (file)
@@ -36,9 +36,10 @@ functionality to your applications.
 User Interface Definition File ``.ui``
 --------------------------------------
 
-When using Qt Designer, you can create user interfaces using Qt Widgets with
-the WYSIWYG form editor, this interface is represented as a widget tree using
-XML. Here is an extract of the beginning of a ``.ui`` file:
+When using *Qt Widgets Designer*, you can create user interfaces using
+Qt Widgets with the WYSIWYG form editor, this interface is represented
+as a widget tree using XML. Here is an extract of the beginning of a
+``.ui`` file:
 
 .. code-block:: xml
 
@@ -96,8 +97,8 @@ the QML file, and optionally, elements defined in Python that are exposed
 to QML to be used.
 
 You can write ``.qml`` files by hand, but also you can use tools like the
-QML Designer that is embedded in Qt Creator. Additionally, there are commercial
-tools like Qt Design Studio that allow you to load designs from other design
+*QML Designer* that is embedded in *Qt Creator*. Additionally, there are commercial
+tools like *Qt Design Studio* that allow you to load designs from other design
 applications.
 
 Here you can find an example of how a ``.qml`` file looks like.
@@ -127,11 +128,11 @@ message on it.
 Qt Creator Python Project File ``.pyproject``
 ---------------------------------------------
 
-For Qt Creator to load and handle Python based projects, a special file is
+For *Qt Creator* to load and handle Python based projects, a special file is
 needed, because C++ based projects could be handle from ``.qmake`` or
 ``CMakeLists.txt`` file, which are not used with Python-based projects.
 
-Old versions of Qt Creator, provided a simple format with the ``.pyqtc``
+Old versions of *Qt Creator*, provided a simple format with the ``.pyqtc``
 extension, which were plain-text files with one-file-per-line::
 
     library/server.py
index 2f8cfd432ca5abd4468a5e6298efdc66180f90b9..3b42a9403163d467f46ece9308b7e81f246ca270 100644 (file)
@@ -65,8 +65,8 @@ is not to affect the user experience compared to other included applications.
 
 .. note:: You can adapt these applications to use your self-made style, but
    you need to be aware that the goal of Widgets is to respect the system
-   style, be careful when changing colors. Check this `simple tutorial
-   <widgetstyling>`_ on how to do so.
+   style, be careful when changing colors. Check this
+   :ref:`simple tutorial <widgetstyling>` on how to do so.
 
 QML
 ---
index ec005a188c92ca25dbdf7971d710ab931e847f16..3afa79b7f8a5309a8051005f6f276fb610449ca7 100644 (file)
@@ -4,7 +4,7 @@ Which IDEs Are Compatible?
 ==========================
 
 |project|, as any other Python module, can be used in any Python-compatible
-IDE, but not all of them will provide extra functionality like Qt Creator does.
+IDE, but not all of them will provide extra functionality like *Qt Creator* does.
 
 Besides writing files, there are some external steps you might want to perform
 in order to help the development of your applications:
@@ -15,8 +15,8 @@ From a terminal:
   :command:`pyside6-uic -i form.ui -o ui_form.py`
 * Generating a Python file from a ``.qrc`` file:
   :command:`pyside6-rcc -i resources.qrc -o rc_resources.py`
-* Opening Qt Designer with the command :command:`pyside6-designer` to
-  edit/create ``.ui`` files.
+* Opening *Qt Widgets Designer* with the command :command:`pyside6-designer`
+  to edit/create ``.ui`` files.
 
 External add-ons/plugins from your favorite IDE might include configuration
 steps to run these commands, or open external tools like Designer and
@@ -47,8 +47,10 @@ that you can install from VS Code while writing the following on the Quick Open
 PyCharm
 -------
 
-You can configure PyCharm to enable external tools, in |project| terms, Qt Designer, and
-Qt Creator. Go to ``File > Settings > tools > PyCharm External Tools``, and include the following
+You can configure PyCharm to enable external tools, in |project| terms,
+*Qt Widgets Designer*, and *Qt Creator*. Go to
+``File > Settings > tools > PyCharm External Tools``, and include the following
 information to add them to your project.
-Later, you will be able to right click a ``.ui`` file, and select ``Qt Designer``,
-``pyside6-uic``, or any tool that you configured this way.
+Later, you will be able to right click a ``.ui`` file, and select
+``Qt Widgets Designer``, ``pyside6-uic``, or any tool that you configured this
+way.
index 39a7f6348dad61485cb9388a499be923593e45d3..9d36061adee3faa596574592d153f49e2ccb078b 100644 (file)
@@ -17,7 +17,7 @@ On **Linux** you might get them with your operating system package manager, on *
 you might get them with ``brew``, and on **Windows** you can download the installer from each
 website.
 
-* **Python**: 3.7+ `[official Python website] <https://www.python.org/downloads/>`_
+* **Python**: 3.9+ `[official Python website] <https://www.python.org/downloads/>`_
 * **Qt:** 6.4+ `[online installer] <https://download.qt.io/official_releases/online_installers/>`_
 * **CMake:** 3.18+ `[official CMake website] <https://cmake.org/download/>`_
 * **Git:** 2.0+. `[official Git website] <https://git-scm.com/downloads>`_
@@ -104,9 +104,9 @@ using **ninja** (instead of make), and considering only the **module subset** of
 :mod:`QtCore <PySide6.QtCore>`, :mod:`QtGui <PySide6.QtGui>`, and
 :mod:`QtWidgets <PySide6.QtWidgets>`.
 
+`CMake Unity Build Mode`_ is used by default for speed-up.
+
 Other important options to consider are:
- * ``--unity``, Activates `CMake Unity Build Mode`_,  which speeds up the
-   build by concatenating source files,
  * ``--cmake``, to specify the path to the cmake binary,
  * ``--reuse-build``, to rebuild only the modified files,
  * ``--openssl=/path/to/openssl/bin``, to use a different path for OpenSSL,
@@ -416,16 +416,17 @@ You can find the ``requirements-doc.txt`` file in the root of the repository.
 
 Starting from 5.15, there are two options to build the documentation:
 
-1. Building rst-only documentation (no API)
+1. Building the base documentation (no API)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The process of parsing Qt headers to generate the PySide API documentation can take several
-minutes, this means that modifying a specific section of the rst files we currently have, might
-become a hard task. You may only care about the ReStructuredText only documentation.
+minutes, this means that modifying a specific section of the documentation we currently have, might
+become a hard task. You may only care about the base documentation, which comprises all the
+documentation except for the API documentation.
 
 To generate this, execute the following command::
 
-    python setup.py build_rst_docs
+    python setup.py build_base_docs
 
 This will generate an ``html/`` directory with the following structure::
 
@@ -443,13 +444,14 @@ files.
 This is useful when updating the general sections of the documentation, adding tutorials,
 modifying the build instructions, and more.
 
-.. note:: In case you are interested in generating the Example Gallery, you
-          would need to first run ``python tools/example_gallery/main.py`` to
-          generate the examples ``rst`` for the gallery.
+.. note:: In case you are interested in only generating the Example Gallery,
+          you would need to run ``python tools/example_gallery/main.py`` to
+          generate the examples ``documentation`` for the gallery. This will
+          also be used internally by the ``build_base_docs`` target
 
 
-2. Building the documentation (rst + API)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+2. Building the documentation (Base + API)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The documentation is being generated using **qdoc** to get the API information, and also **sphinx**
 for the local Python related notes.
@@ -474,9 +476,9 @@ to get the HTML files), you can go to the generated
 You can add ``-j X``, to perform the build process in parallel with
 X processes.
 
-.. note:: The :command:`apidoc` make target builds offline documentation in ``QCH`` (Qt Creator Help)
-   format by default. You can switch to building for the online use with the ``--doc-build-online``
-   configure option.
+.. note:: The :command:`apidoc` make target builds offline documentation in ``QCH``
+   (Qt Compressed Help) format by default. You can switch to building for the
+   online use with the ``--doc-build-online`` configure option.
 
 The target executes several steps:
 
@@ -486,7 +488,7 @@ The target executes several steps:
 
 Re-running the command will not execute step 1 unless the file
 ``qdoc-output/webxml/qtcore-index.webxml`` is removed from the build tree.
-Similarly, step 2 will not be executed unless the file ``rst/PySide6/QtCore/index.rst``
+Similarly, step 2 will not be executed unless the file ``base/PySide6/QtCore/index.rst``
 is removed.
 
 Finally, you will get a ``html`` directory containing all the generated documentation. The offline
@@ -496,18 +498,18 @@ can find ``Shiboken.qch`` in the build directory, ``build/<your_env_name>/build/
 If you want to temporarily change a ``.rst`` file to examine the impact on
 formatting, you can re-run ``sphinx`` in the ``doc`` directory::
 
-    sphinx-build rst html
+    sphinx-build base html
 
 Viewing offline documentation
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-The offline documentation (QCH) can be viewed using the Qt Creator IDE or Qt Assistant, which is
-a standalone application for viewing QCH files.
+The offline documentation (QCH) can be viewed using the *Qt Creator* IDE or
+*Qt Assistant*, which is a standalone application for viewing QCH files.
 
-To view the QCH using Qt Creator, following the instructions outlined in
-`Using Qt Creator Help Mode <https://doc.qt.io/qtcreator/creator-help.html>`_. If you chose to
-use Qt Assistant instead, use the following command to register the QCH file before launching
-Qt Assistant::
+To view the QCH using *Qt Creator*, following the instructions outlined in
+`Using Qt Creator Help Mode <https://doc.qt.io/qtcreator/creator-help.html>`_.
+If you chose to use *Qt Assistant* instead, use the following command to register
+the QCH file before launching *Qt Assistant*::
 
     assistant -register PySide.qch
 
@@ -519,7 +521,7 @@ Shiboken documentation. This can fail if
 
 * the default ``QCH`` format is used; in which case the required ``objects.inv``
   files are not generated. Use ``--doc-build-online``.
-* rst-only and full doc builds are mixed, resulting in wrong values for the
+* base and full doc builds are mixed, resulting in wrong values for the
   intersphinx location in the CMake files. Re-run ``cmake`` to fix this.
 
 Using the internal tools
index 1793625155ec35cb19f633b26d6cd0edba412862..113edb686c1d92065dcf323a98ae90a41169fab5 100644 (file)
@@ -68,79 +68,8 @@ which is the original QtCore library.
   Adding the full URL because it's a different sphinx project.
 .. _`Shiboken Documentation`: https://doc.qt.io/qtforpython/shiboken6/gettingstarted.html
 
-.. _package_tools:
-
 Tools Included
 --------------
 
-Following the same idea from the modules, we also include in the packages
-(wheels) Qt tools that are important for any Qt application development
-workflow, like ``uic``, ``rcc``, etc.
-
-All the tools **must** be used from the PySide wrappers, and not directly.
-For example, if exploring the ``site-packages/`` directory on your installation
-you find ``uic.exe`` (on Windows), you should not click on that, and use
-``pyside6-uic.exe`` instead.
-The reason for this is the proper setup of PATHs, plugins, and more,
-to properly work with the installed Python package.
-
-Here you can find all the tools we include in |project| starting
-from 6.3.0, grouped by different topics:
-
-Project development
-~~~~~~~~~~~~~~~~~~~
-
-* ``pyside6-project``, to build Qt Designer forms (``.ui`` files),
-  resource files (``.qrc``) and QML type files (``.qmltype``) from
-  a ``.pyproject`` file.
-
-Widget Development
-~~~~~~~~~~~~~~~~~~
-
-* ``pyside6-designer``, drag-and-drop tool for designing Widget UIs (generates ``.ui`` files,
-    see :ref:`using_ui_files`).
-* ``pyside6-uic``, to generate Python code from ``.ui`` form files.
-* ``pyside6-rcc``, to generate serialized data from ``.qrc`` resources files.
-  Keep in mind these files can be used in other non-widget projects.
-
-QML Development
-~~~~~~~~~~~~~~~
-
-* ``pyside6-qmllint``, that verifies the syntactic validity of QML files.
-* ``pyside6-qmltyperegistrar``, to read metatypes files and generate
-  files that contain the necessary code to register all the types marked with
-  relevant macros.
-* ``pyside6-qmlimportscanner``, to identify the QML modules imported from a
-    project/QML files and dump the result as a JSON array.
-* ``pyside6-qmlcachegen``, to compile QML to bytecode at compile time for bundling inside the
-    binary.
-
-Translations
-~~~~~~~~~~~~
-
-* ``pyside6-linguist``, for translating text in applications.
-* ``pyside6-lrelease``, to create run-time translation files for the application.
-* ``pyside6-lupdate``, to synchronize source code and translations.
-
-Qt Help
-~~~~~~~
-
-* ``pyside6-assistant``, for viewing online documentation in Qt Help file format.
-  Read more about the formats on the `QtHelp Framework`_ page.
-
-.. _`QtHelp Framework`: https://doc.qt.io/qt-6/qthelp-framework.html
-
-PySide Utilities
-~~~~~~~~~~~~~~~~
-
-* ``pyside6-genpyi``, to generate Python stubs (``.pyi`` files) for Qt modules.
-* ``pyside6-metaobjectdump``, a tool to print out the metatype information in
-  JSON to be used as input for ``qmltyperegistrar``.
-
-Deployment
-~~~~~~~~~~
-
-* ``pyside6-deploy``, to deploy PySide6 applications to desktop platforms -
-  Linux, Windows and macOS.
-* ``pyside6-android-deploy``, to deploy PySide6 application as an Android app
-  targeting different Android platforms - aarch64, armv7a, i686, x86_64.
+PySide6 comes bundled with a set of tools that assist in making the development experience with
+PySide6 more efficient. The list of tools can be found :ref:`here <package_tools>`.
index c704b33717981151f699a0f76b931d33e41cc6e4..f688acd90496e5cc8e5a374c13c17aae76117d8e 100644 (file)
@@ -12,11 +12,8 @@ Requirements
 * ``sphinx`` package for the documentation (optional).
 * Check the platform dependencies of `Qt for Windows`_.
 
-.. note:: Python 3.8.0 was missing some API required for PySide/Shiboken so it's not possible
-    to use it for a Windows build.
-
 .. note:: The Python provided by the Microsoft Store is not compatible with PySide. Please
-    use https://python.org/download to get a Python Interpreter.
+    use https://www.python.org/downloads/ to get a Python Interpreter.
 
 .. _MSVC2022: https://visualstudio.microsoft.com/downloads/
 .. _OpenSSL: https://sourceforge.net/projects/openssl/
index 83582835b6d7ec3015b93b5dd1f9a76aad8602b0..1bb28f9c12b395209224756772e01f1615c82759 100644 (file)
@@ -99,7 +99,7 @@ Documentation
 
         PySide API reference.
         +++
-        .. button-ref:: api
+        .. button-ref:: pyside-api
             :color: primary
             :outline:
             :expand:
index d1e095ce6509c880048a6df0c6851b5667733693..e972fac4c922eaf65ebb91d1b7127b03bf6837ba 100644 (file)
@@ -37,7 +37,6 @@ r"""
     :license: BSD, see LICENSE for details.
 """
 
-import sys
 try:
     from hashlib import md5
 except ImportError:
@@ -49,10 +48,7 @@ from docutils.parsers.rst import directives, Directive
 from sphinx.ext.graphviz import render_dot_html, render_dot_latex
 
 from inheritance_graph import InheritanceGraph
-from import_inheritance import (get_inheritance_entries_by_import,
-                                InheritanceException)
-from json_inheritance import (is_inheritance_from_json_enabled,
-                              get_inheritance_entries_from_json)
+from import_inheritance import (InheritanceException)
 
 
 class inheritance_diagram(nodes.General, nodes.Element):
@@ -112,27 +108,6 @@ def get_graph_hash(node):
     return md5(hashString.encode('utf-8')).hexdigest()[-10:]
 
 
-def fix_class_name(name):
-    """Fix duplicated modules 'PySide6.QtCore.PySide6.QtCore.QObject'"""
-    mod_pos = name.rfind('.PySide')
-    return name[mod_pos + 1:] if mod_pos != -1 else name
-
-
-def expand_ref_uri(uri):
-    """Fix a ref URI like 'QObject.html#PySide6.QtCore.PySide6.QtCore.QObject'
-       to point from the image directory back to the HTML directory."""
-    anchor_pos = uri.find('#')
-    if anchor_pos == -1:
-        return uri
-    # Determine the path from the anchor "#PySide6.QtCore.PySide6.QtCore.QObject"
-    class_name = fix_class_name(uri[anchor_pos + 1:])
-    path = '../'
-    modules = class_name.split('.')
-    for m in range(min(2, len(modules))):
-        path += f'{modules[m]}/'
-    return path + uri[:anchor_pos]  # Strip anchor
-
-
 def html_visit_inheritance_diagram(self, node):
     """
     Output the graph for HTML.  This will insert a PNG with clickable
@@ -149,7 +124,7 @@ def html_visit_inheritance_diagram(self, node):
         ref_title = child.get('reftitle')
         uri = child.get('refuri')
         if uri and ref_title:
-            urls[fix_class_name(ref_title)] = expand_ref_uri(uri)
+            urls[ref_title] = uri
 
     dotcode = graph.generate_dot(name, urls, env=self.builder.env)
     render_dot_html(self, node, dotcode, {}, 'inheritance', 'inheritance',
index e45ebb176ab579923a61b228790eb84c393563bb..00e0ac4867414cd3f228aa830ae6463aa52b3aea 100644 (file)
@@ -3,8 +3,7 @@
 
 import sys
 
-from import_inheritance import (get_inheritance_entries_by_import,
-                                InheritanceException)
+from import_inheritance import (get_inheritance_entries_by_import)
 from json_inheritance import (is_inheritance_from_json_enabled,
                               get_inheritance_entries_from_json)
 
index bffb49b7e7517569470d486a87b7ecb1dcf8d0b2..8e77a46168964543c87ee3ddb283a09c374f767a 100644 (file)
@@ -44,7 +44,7 @@ Qt Modules Supported by Qt for Python
 
     .. grid-item-card:: :mod:`QtDesigner <PySide6.QtDesigner>`
 
-        Provides classes to extend Qt Designer.
+        Provides classes to extend *Qt Widgets Designer*.
 
     .. grid-item-card:: :mod:`QtGui <PySide6.QtGui>`
 
@@ -114,6 +114,10 @@ Qt Modules Supported by Qt for Python
 
         Provides classes for setting up the controls from C++.
 
+    .. grid-item-card:: :mod:`QtQuickTest <PySide6.QtQuickTest>`
+
+       A unit test framework for QML applications where test cases are written as JavaScript functions.
+
     .. grid-item-card:: :mod:`QtQuickWidgets <PySide6.QtQuickWidgets>`
 
         Provides the QQuickWidget class for embedding Qt Quick in widget-based applications.
@@ -169,7 +173,7 @@ Qt Modules Supported by Qt for Python
 
     .. grid-item-card:: :mod:`QtUiTools <PySide6.QtUiTools>`
 
-        Provides classes to handle forms created with Qt Designer.
+        Provides classes to handle forms created with *Qt Widgets Designer*.
 
     .. grid-item-card:: :mod:`Qt WebChannel <PySide6.QtWebChannel>`
 
index 66f8e31e78a2f72d4795c95a9f4ebe4a5083dbaa..8e2834ccef91d819ff5ed8163b63ae7f8584143d 100644 (file)
@@ -11,7 +11,6 @@ from os import path
 from docutils import nodes
 from docutils.parsers.rst import Directive, directives
 
-from sphinx import addnodes
 from sphinx.util import parselinenos
 
 
@@ -69,7 +68,7 @@ class PySideInclude(Directive):
         codec_info = codecs.lookup(encoding)
         try:
             f = codecs.StreamReaderWriter(open(fn, 'Ub'),
-                    codec_info[2], codec_info[3], 'strict')
+                                          codec_info[2], codec_info[3], 'strict')
             lines = f.readlines()
             f.close()
         except (IOError, OSError):
@@ -103,10 +102,10 @@ class PySideInclude(Directive):
             lines = [lines[i] for i in linelist]
 
         startafter = self.options.get('start-after')
-        endbefore  = self.options.get('end-before')
-        prepend    = self.options.get('prepend')
-        append     = self.options.get('append')
-        snippet    = self.options.get('snippet')
+        endbefore = self.options.get('end-before')
+        prepend = self.options.get('prepend')
+        append = self.options.get('append')
+        snippet = self.options.get('snippet')
 
         if snippet:
             startafter = "//![%s]" % snippet
index 0223e50ee6aec467a339279374717fd29398340d..d9d4343663413aaabc11bf633d5decf084468ce9 100644 (file)
@@ -80,6 +80,12 @@ if __name__ == "__main__":
     parser.add_argument("--verbose", dest="verbose", action="store_true", default=False)
 
     args = parser.parse_args()
+
+    core_index = Path(args.doc_data_dir) / "webxml" / "qtcore-index.webxml"
+    if core_index.is_file():
+        print(f"qdoc_spawner: {core_index} already exists, bailing out")
+        sys.exit(0)
+
     files_prepare, files_single_exec = get_qdocconf_files()
 
     parallel = args.parallel
index aae4bccf8064518388dc2f9876ea9f49505208ea..677371c45cce5d2e3403333447b7d8fcb42163f4 100644 (file)
@@ -8,7 +8,6 @@ Tool to run qtattributionsscanner and convert its output to rst
 import os
 import json
 import subprocess
-import sys
 import warnings
 from argparse import ArgumentParser, RawTextHelpFormatter
 from pathlib import Path
@@ -22,8 +21,8 @@ libexec_dir = None
 
 def indent(lines, indent):
     result = ''
-    for l in lines:
-        result = f"{result}{indent}{l}\n"
+    for line in lines:
+        result = f"{result}{indent}{line}\n"
     return result
 
 
@@ -96,7 +95,7 @@ def runScanner(directory, targetFileName, libexec_dir):
             url = entry['Homepage']
             version = entry['Version']
             if url and version:
-                content = f"{content}{rstUrl('Project Homepage', url)}, upstream version: {version}\n\n"
+                content = f"{content}{rstUrl('Project Homepage', url)}, upstream version: {version}\n\n"  # noqa E:501
             copyright = entry['Copyright']
             if copyright:
                 content += rstLiteralBlockFromText(copyright)
diff --git a/sources/pyside6/doc/qtmodules/pyside-qtquicktest.qdocconf.in b/sources/pyside6/doc/qtmodules/pyside-qtquicktest.qdocconf.in
new file mode 100644 (file)
index 0000000..1d83975
--- /dev/null
@@ -0,0 +1,3 @@
+include(@QT_SRC_DIR@/../qtdeclarative/src/qmltest/doc/qtqmltest.qdocconf)
+includepaths += -I @QT_SRC_DIR@/../qtdeclarative/src/qmltest
+include(../pyside-config.qdocconf)
diff --git a/sources/pyside6/doc/tools/index.rst b/sources/pyside6/doc/tools/index.rst
new file mode 100644 (file)
index 0000000..b421a42
--- /dev/null
@@ -0,0 +1,211 @@
+.. _package_tools:
+
+Tools
+=====
+
+Following the same idea from the modules, we also include in the packages
+(wheels) Qt tools that are important for any Qt application development
+workflow, like ``uic``, ``rcc``, etc.
+
+All the tools **must** be used from the PySide wrappers, and not directly.
+For example, if exploring the ``site-packages/`` directory on your installation
+you find ``uic.exe`` (on Windows), you should not click on that, and use
+``pyside6-uic.exe`` instead.
+The reason for this is the proper setup of PATHs, plugins, and more,
+to properly work with the installed Python package.
+
+Here you can find all the tools we include in |project| starting
+from 6.3.0, grouped by different topics:
+
+Project development
+~~~~~~~~~~~~~~~~~~~
+
+.. grid:: 2
+    :gutter: 3 3 4 5
+
+    .. grid-item-card:: ``pyside6-project``
+        :link: pyside6-project
+        :link-type: ref
+
+        to build *Qt Widgets Designer* forms (``.ui`` files),
+        resource files (``.qrc``) and QML type files (``.qmltype``)
+        from a ``.pyproject`` file.
+
+Widget Development
+~~~~~~~~~~~~~~~~~~
+
+.. grid:: 2
+    :gutter: 3 3 4 5
+
+    .. grid-item-card:: ``pyside6-designer``
+        :link: pyside6-designer
+        :link-type: ref
+
+        drag-and-drop tool for designing Widget UIs (generates ``.ui`` files,
+        see :ref:`using_ui_files`).
+
+    .. grid-item-card:: ``pyside6-uic``
+        :link: pyside6-uic
+        :link-type: ref
+
+        to generate Python code from ``.ui`` form files.
+
+    .. grid-item-card:: ``pyside6-rcc``
+        :link: pyside6-rcc
+        :link-type: ref
+
+        to generate serialized data from ``.qrc`` resources files.
+        Keep in mind these files can be used in other non-widget projects.
+
+
+QML Development
+~~~~~~~~~~~~~~~
+
+.. grid:: 2
+    :gutter: 3 3 4 5
+
+    .. grid-item-card:: ``pyside6-qmllint``
+        :link: pyside6-qmllint
+        :link-type: ref
+
+        that verifies the syntactic validity of QML files.
+
+    .. grid-item-card:: ``pyside6-qmltyperegistrar``
+        :link: pyside6-qmltyperegistrar
+        :link-type: ref
+
+        to read metatypes files and generate files that contain the necessary
+        code to register all the types marked with relevant macros.
+
+    .. grid-item-card:: ``pyside6-qmlimportscanner``
+        :link: pyside6-qmlimportscanner
+        :link-type: ref
+
+        to identify the QML modules imported from a
+        project/QML files and dump the result as a JSON array.
+
+    .. grid-item-card:: ``pyside6-qmlcachegen``
+        :link: pyside6-qmlcachegen
+        :link-type: ref
+
+        to compile QML to bytecode at compile time for bundling inside the
+        binary.
+
+    .. grid-item-card:: ``pyside6-qml``
+        :link: pyside6-qml
+        :link-type: ref
+
+        to enable quick prototyping with QML files. This tool mimics some of
+        the capabilities of Qt's ``QML`` runtime utility by
+        directly invoking QQmlEngine/QQuickView.
+
+Translations
+~~~~~~~~~~~~
+
+.. grid:: 2
+    :gutter: 3 3 4 5
+
+    .. grid-item-card:: ``pyside6-linguist``
+        :link: pyside6-linguist
+        :link-type: ref
+
+        for translating text in applications.
+
+    .. grid-item-card:: ``pyside6-lrelease``
+        :link: pyside6-lrelease
+        :link-type: ref
+
+        to create run-time translation files for the application.
+
+    .. grid-item-card:: ``pyside6-lupdate``
+        :link: pyside6-lupdate
+        :link-type: ref
+
+        to synchronize source code and translations.
+
+Qt Help
+~~~~~~~
+
+.. grid:: 2
+    :gutter: 3 3 4 5
+
+    .. grid-item-card:: ``pyside6-assistant``
+        :link: pyside6-assistant
+        :link-type: ref
+
+        for viewing online documentation in Qt Help file format.
+        Read more about the formats on the `QtHelp Framework`_ page.
+
+.. _`QtHelp Framework`: https://doc.qt.io/qt-6/qthelp-framework.html
+
+PySide Utilities
+~~~~~~~~~~~~~~~~
+
+.. grid:: 2
+    :gutter: 3 3 4 5
+
+    .. grid-item-card:: ``pyside6-genpyi``
+        :link: pyside6-genpyi
+        :link-type: ref
+
+        to generate Python stubs (``.pyi`` files) for Qt modules.
+
+    .. grid-item-card:: ``pyside6-metaobjectdump``
+        :link: pyside6-metaobjectdump
+        :link-type: ref
+
+        a tool to print out the metatype information in JSON to be used as
+        input for ``qmltyperegistrar``.
+
+Deployment
+~~~~~~~~~~
+
+.. grid:: 2
+    :gutter: 3 3 4 5
+
+    .. grid-item-card:: ``pyside6-deploy``
+        :link: pyside6-deploy
+        :link-type: ref
+
+        to deploy PySide6 applications to desktop platforms - Linux, Windows
+        and macOS.
+
+    .. grid-item-card:: ``pyside6-android-deploy``
+        :link: pyside6-android-deploy
+        :link-type: ref
+
+        to deploy PySide6 application as an Android app targeting different
+        Android platforms - aarch64, armv7a, i686, x86_64.
+
+Shader Tools
+~~~~~~~~~~~~
+
+.. grid:: 2
+    :gutter: 3 3 4 5
+
+    .. grid-item-card:: ``pyside6-qsb``
+        :link: pyside6-qsb
+        :link-type: ref
+
+        a command-line tool provided by the Qt Shader Tools modules to
+        generate and inspect .qsb files.
+
+Qt Quick 3D
+~~~~~~~~~~~
+
+.. grid:: 2
+    :gutter: 3 3 4 5
+
+    .. grid-item-card:: ``pyside6-balsam``
+        :link: pyside6-balsam
+        :link-type: ref
+
+        a command line tool that takes assets created in digital content
+        creation tools like Maya, 3ds Max or Blender and converts them into an
+        efficient runtime format for use with Qt Quick 3D.
+
+    .. grid-item-card:: ``pyside6-balsamui``
+        :link: pyside6-balsamui
+        :link-type: ref
+
+        a graphical user interface for the ``pyside6-balsam`` tool.
diff --git a/sources/pyside6/doc/tools/pyside-assistant.rst b/sources/pyside6/doc/tools/pyside-assistant.rst
new file mode 100644 (file)
index 0000000..c9b3470
--- /dev/null
@@ -0,0 +1,21 @@
+.. _pyside6-assistant:
+
+pyside6-assistant
+=================
+
+``pyside6-assistant`` is a tool that wraps `Qt Assistant`_, the help
+viewer of Qt for use with the Qt help file format (see `The Qt Help Framework`_).
+
+The version of assistant shipped with Qt for Python does not contain
+any documentation.
+
+You can build the Qt for Python documentation in the Qt help file format
+(see :ref:`building_documentation`) and register it for use in `Preferences`
+dialog of ``pyside6-assistant`` (`Edit/Preferences`).
+
+.. image:: pyside6-assistant_screenshot.webp
+    :width: 381
+    :alt: PySide6 Assistant Screenshot
+
+.. _`Qt Assistant`: https://doc.qt.io/qt-6/qtassistant-index.html
+.. _`The Qt Help Framework`: https://doc.qt.io/qt-6/qthelp-framework.html
diff --git a/sources/pyside6/doc/tools/pyside-designer.rst b/sources/pyside6/doc/tools/pyside-designer.rst
new file mode 100644 (file)
index 0000000..4cde6b2
--- /dev/null
@@ -0,0 +1,91 @@
+.. _pyside6-designer:
+
+pyside6-designer
+================
+
+``pyside6-designer`` is a tool that wraps the `Qt Widgets Designer`_,
+to enable you to design Qt Widgets applications with a *drag-and-drop*
+approach.
+
+.. image:: pyside6-designer_screenshot.webp
+    :width: 100%
+    :alt: PySide6 Designer Screenshot
+
+Usage
+-----
+
+With ``pyside6-designer`` you can design your application in a simple way,
+to later save the end result in a ``.ui`` file. When you start the tool, you
+will see a dialog to select the base window: a QWidget, a QMainWindow, etc.
+
+.. image:: pyside6-designer_base_screenshot.webp
+    :width: 50%
+    :alt: PySide6 Designer Initial Screenshot
+
+Once you select one of those options, you can start placing widgets
+into the interface, and have access to the whole structure, properties,
+and more.
+
+.. image:: pyside6-designer_sections_screenshot.webp
+    :width: 100%
+    :alt: PySide6 Designer Initial Screenshot
+
+A simple distinction of the areas you might use is described in the
+previous screenshot. In the section **1** you will find all the elements
+you can use in your application, which is the area **2**.
+The application designs follows a hierarchical configuration,
+in **3** you can see the structure of the example which contains
+only a ``QMainWindow`` and a ``QPushButton``. Lastly
+you can access and modify the properties of the item in **4**,
+where you could adjust dimensions, names, etc.
+
+
+When your application is finished, you will save your design in a ``.ui``
+file. This ``.ui`` file can later be converted into a Python file,
+with the help of the :ref:`pyside6-uic` tool. You can find
+more details of this process in: :ref:`using_ui_files`.
+
+If you are interested in more functionality of the tool, you can check
+the official `Qt Widgets Designer Manual`_.
+
+
+Custom Widgets
+--------------
+
+One of the features that the `Qt Widgets Designer`_ provides is the possibility
+of loading custom widgets, in order to facilitate the development with ad-hoc
+widgets.
+
+On the following screenshot, you can see a new component on the left column
+that is already added on the main widget, a tic-tac-toe custom widget.
+
+.. image:: pyside6-designer_customwidgets_screenshot.webp
+    :width: 100%
+    :alt: PySide6 Designer Custom Widgets Screenshot
+
+To achieve this, you need to register a custom widget by setting the environment
+variable ``PYSIDE_DESIGNER_PLUGINS`` to the directory where your register file
+is located. The registration file for the tic-tac-toe widget looks like this:
+
+.. code-block:: Python
+
+    from tictactoe import TicTacToe
+    from tictactoeplugin import TicTacToePlugin
+
+    from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
+
+
+    if __name__ == '__main__':
+        QPyDesignerCustomWidgetCollection.addCustomWidget(TicTacToePlugin())
+
+As you can see in the previous code, ``TicTacToe`` is the custom widget,
+imported from a different file, and the ``TicTacToePlugin`` is the interface
+layer for `Qt Widgets Designer`_ to recognize it.
+We provide a helper class, ``QPyDesignerCustomWidgetCollection``, to
+simplify the registration process.
+
+If you are interested in all the details of this specific case, you can
+check the :ref:`task-menu-extension-example`.
+
+.. _`Qt Widgets Designer`: https://doc.qt.io/qt-6/qtdesigner-manual.html
+.. _`Qt Widgets Designer Manual`: https://doc.qt.io/qt-6/qtdesigner-manual.html
diff --git a/sources/pyside6/doc/tools/pyside-genpyi.rst b/sources/pyside6/doc/tools/pyside-genpyi.rst
new file mode 100644 (file)
index 0000000..0240c50
--- /dev/null
@@ -0,0 +1,52 @@
+.. _pyside6-genpyi:
+
+pyside6-genpyi
+==============
+
+`pyside6-genpyi` is a command line tool to generate Python stub files
+(.pyi) for PySide modules. Stub files define signatures of all classes,
+methods (including overloads), constants and enums of the PySide
+modules. Signatures also contain type hints. This helps PySide integrate
+with Python type checkers and IDEs. For example, if you use any function
+from the Qt API with PySide, your IDE's function lookup feature will
+show you the function signature and its parameters and return value
+including types.
+
+PySide6 already ships with stub files that were generated with
+`pyside6-genpyi`. However, if you want to generate new stub files for
+several (or all) modules, for example to toggle a few features, you can
+run `pyside6-genpyi` manually. If you want to generate stub files for
+your own custom module, refer to :ref:`shiboken6-genpyi`.
+
+
+Usage
+-----
+
+To generate stub files for a PySide module, run the following command:
+
+.. code-block:: bash
+
+    pyside6-genpyi <module_names> [OPTIONS]
+
+where `<module_names>` is a space-separated list of module names (the
+modules must be importable from the working directory) and where
+`[OPTIONS]` can be one of the following:
+
+* **--quiet**: Run the tool quietly without output to stdout.
+* **--outpath <output_dir>**: Specify the output directory for the
+  generated stub files. If not specified, the stub files are generated
+  in the location of the module binary.
+* **--sys-path <paths>**: Prepend the system path (`sys.path`) with a
+  space-separated list of strings `<paths>`. This is useful if the
+  module is not installed in a default lookup location.
+* **--feature <features>**: A space-separate list of optional PySide
+  features to enable (see :ref:`pysideapi2`). This option has no effect
+  when using PyPy. Currently, the following features are available:
+
+  * **snake_case**: All methods in the module are switched from
+    ``camelCase`` to ``snake_case``. A single upper case letter is
+    replaced by an underscore and the lower case letter.
+  * **true_property**: All getter and setter functions in the module
+    which are marked as a property in the Qt6 docs are replaced by Python
+    property objects. Properties are also listed as such in the according
+    QMetaObject of a class.
diff --git a/sources/pyside6/doc/tools/pyside-linguist.rst b/sources/pyside6/doc/tools/pyside-linguist.rst
new file mode 100644 (file)
index 0000000..e13124a
--- /dev/null
@@ -0,0 +1,20 @@
+.. _pyside6-linguist:
+
+pyside6-linguist
+=================
+
+``pyside6-linguist`` is a tool that wraps `Qt Linguist`_, Qt's tool to
+translate user interfaces and manage application localizations. It
+supports Qt's own TS file format as well as the XML Localization
+Interchange File Format (XLIFF). There are no differences between the
+version bundled with PySide and the one from Qt.
+
+For more information on how to use this tool, read Qt's documentation
+here: `Qt Linguist`_. Read more about how to translate PySide
+applications here: :ref:`translations`.
+
+.. image:: pyside6-linguist_screenshot.webp
+    :width: 500
+    :alt: PySide6 Linguist Screenshot
+
+.. _`Qt Linguist`: https://doc.qt.io/qt-6/qtlinguist-index.html
diff --git a/sources/pyside6/doc/tools/pyside-lrelease.rst b/sources/pyside6/doc/tools/pyside-lrelease.rst
new file mode 100644 (file)
index 0000000..7c628f2
--- /dev/null
@@ -0,0 +1,25 @@
+.. _pyside6-lrelease:
+
+pyside6-lrelease
+================
+
+.. note:: This tool is automatically called by :ref:`pyside6-project`
+   so you don't need to call it manually. *Qt Creator* will take care
+   of this step as well while executing a project.
+
+``pyside6-lrelease`` is a command line tool wrapping `lrelease`_. It produces
+``.qm`` files out of ``.ts`` files. The ``.qm`` file format is a compact binary
+format that the localized application uses. It provides extremely fast lookup
+for translations (see :ref:`translations`).
+
+Usage
+-----
+
+To convert a ``.ts`` file of the :ref:`qt-linguist-example`
+into its binary representation, run:
+
+.. code-block:: bash
+
+    pyside6-lrelease example_de.ts -qm example_de.qm
+
+.. _`lrelease`: https://doc.qt.io/qt-6/linguist-lrelease.html
diff --git a/sources/pyside6/doc/tools/pyside-lupdate.rst b/sources/pyside6/doc/tools/pyside-lupdate.rst
new file mode 100644 (file)
index 0000000..1c0d73c
--- /dev/null
@@ -0,0 +1,23 @@
+.. _pyside6-lupdate:
+
+pyside6-lupdate
+===============
+
+.. note:: This tool is automatically called by :ref:`pyside6-project`
+   so you don't need to call it manually.
+
+``pyside6-lupdate`` is a command line tool wrapping `lupdate`_. It finds
+translatable strings in Python, ``.ui``, and ``.qml`` files and generates or
+updates ``.ts`` files (see :ref:`translations`).
+
+Usage
+-----
+
+To create or update the ``.ts`` file of the :ref:`qt-linguist-example`,
+run:
+
+.. code-block:: bash
+
+    pyside6-lupdate main.py main.qml form.ui -ts example_de.ts
+
+.. _`lupdate`: https://doc.qt.io/qt-6/linguist-lupdate.html
diff --git a/sources/pyside6/doc/tools/pyside-metaobjectdump.rst b/sources/pyside6/doc/tools/pyside-metaobjectdump.rst
new file mode 100644 (file)
index 0000000..1522b7a
--- /dev/null
@@ -0,0 +1,92 @@
+.. _pyside6-metaobjectdump:
+
+pyside6-metaobjectdump
+======================
+
+``pyside6-metaobjectdump`` is a command line tool. It scans Python source
+files and dumps out information on classes to be registered with QML in
+JSON-format. This serves as input for the :ref:`pyside6-qmltyperegistrar` tool.
+
+The tool is the equivalent of the `moc`_ tool in Qt / C++.
+
+It is automatically run by the :ref:`pyside6-project` tool
+when passing the ``qmllint`` argument instructing it to check
+the QML source files.
+
+Usage
+-----
+
+Classes to be registered with QML are indicated by QML decorators
+like :deco:`QmlElement`. Invoking:
+
+.. code-block:: bash
+
+    pyside6-metaobjectdump birthdayparty.py
+
+produces the JSON data on stdout:
+
+.. code-block:: json
+
+    [
+        {
+            "classes": [
+                {
+                    "className": "BirthdayParty",
+                    "qualifiedClassName": "BirthdayParty",
+                    "object": true,
+                    "superClasses": [
+                        {
+                            "access": "public",
+                            "name": "QObject"
+                        }
+                    ],
+                    "classInfos": [
+                        {
+                            "name": "QML.Element",
+                            "value": "auto"
+                        }
+                    ],
+                    "properties": [
+                        {
+                            "name": "host",
+                            "type": "Person",
+                            "index": 0,
+                            "read": "host",
+                            "notify": "host_changed",
+                            "write": "host"
+                        },
+                        {
+                            "name": "guests",
+                            "type": "QQmlListProperty<Person>",
+                            "index": 1
+                        }
+                    ],
+                    "signals": [
+                        {
+                            "access": "public",
+                            "name": "host_changed",
+                            "arguments": [],
+                            "returnType": "void"
+                        },
+                        {
+                            "access": "public",
+                            "name": "guests_changed",
+                            "arguments": [],
+                            "returnType": "void"
+                        }
+                    ]
+                }
+            ],
+            "outputRevision": 68,
+            "QML_IMPORT_NAME": "People",
+            "QML_IMPORT_MAJOR_VERSION": 1,
+            "QML_IMPORT_MINOR_VERSION": 0,
+            "QT_MODULES": [
+                "QtCore",
+                "QtQml"
+            ],
+            "inputFile": ".../examples/qml/tutorials/extending-qml-advanced/advanced1-Base-project/birthdayparty.py"
+        }
+    ]
+
+.. _`moc`: https://doc.qt.io/qt-6/moc.html
diff --git a/sources/pyside6/doc/tools/pyside-project.rst b/sources/pyside6/doc/tools/pyside-project.rst
new file mode 100644 (file)
index 0000000..0359e1b
--- /dev/null
@@ -0,0 +1,64 @@
+.. _pyside6-project:
+
+pyside6-project
+===============
+
+`pyside6-project` is a command line tool for creating, building and deploying
+|project| applications. It operates on a project file which is also used by
+`Qt Creator`_.
+
+Project file format
+-------------------
+
+The project file format is a simple `JSON`_-based format with the suffix
+``.pyproject`` listing all files of the project excluding generated files
+(typically ``.py``, ``.qml``, ``.qrc``, ``.ts``, or ``.ui`` files):
+
+.. code-block:: json
+
+    {
+        "files": ["main.py"]
+    }
+
+
+Usage
+-----
+
+The tool has several subcommands. New projects can be created using
+the below commands, passing the project name (directory):
+
+*new-ui*
+    Creates a new QtWidgets project with a *Qt Widgets Designer*-based main
+    window.
+
+*new-widget*
+    Creates a new QtWidgets project with a main window.
+
+*new-quick*
+    Creates a new QtQuick project.
+
+The other commands take the project file as an argument.
+It is also possible to specify a directory containing the project file.
+
+*build*
+    Builds the project, generating the required build artifacts
+    (see :ref:`using_ui_files`, :ref:`using_qrc_files`).
+
+*run*
+    Builds the project and runs the main.
+
+*deploy*
+    Deploys the application (see see :ref:`pyside6-deploy`).
+
+*lupdate*
+    Updates translation (.ts) files (see :ref:`translations`).
+
+*clean*
+    Cleans the build artifacts.
+
+*qmllint*
+    Runs the ``qmllint`` tool, checking the QML files.
+
+
+.. _`Qt Creator`: https://www.qt.io/product/development-tools
+.. _`JSON`: https://www.json.org/
diff --git a/sources/pyside6/doc/tools/pyside-qml.rst b/sources/pyside6/doc/tools/pyside-qml.rst
new file mode 100644 (file)
index 0000000..0502dd9
--- /dev/null
@@ -0,0 +1,84 @@
+.. _pyside6-qml:
+
+pyside6-qml
+===========
+
+``pyside6-qml``  mimics some capabilities of Qt's `qml <qml_runtime>`_ runtime utility by directly
+invoking QQmlEngine/QQuickView. It enables prototyping with QML/QtQuick without the need to write
+any Python code that loads the QML files either through `QQmlApplicationEngine <qqmlappengine>`_ or
+the `QQuickView <qquickview>`_ class. The tool also detects the QML classes implemented in Python
+and registers them with the QML type system.
+
+Usage
+-----
+
+Consider the example `Extending QML - Plugins Example <extending_qml_example>`_. This example does
+not have a Python file with a ``main`` function that initializes a QmlEngine to load the QML file
+``app.qml``. You can run the example by running
+
+.. code-block:: bash
+
+    pyside6-qml examples/qml/tutorials/extending-qml/chapter6-plugins/app.qml -I examples/qml/tutorials/extending-qml/chapter6-plugins/Charts
+
+The ``-I`` flag is used to point ``pyside6-qml`` to the folder containing Python files that
+implement QML classes.
+
+Command Line Options
+--------------------
+
+Here are all the command line options of ``pyside6-qml``:
+
+Arguments
+^^^^^^^^^
+
+* **file**: This option refers to the QML file to be loaded by ``pyside6-qml``. This option does not
+  have a name or a flag. Therefore, this option should be the first option supplied to
+  ``pyside6-qml``. For example,
+
+.. code-block:: bash
+
+    pyside6-qml /path/to/test.qml
+
+Options
+^^^^^^^
+
+* **--module-paths/-I**: Specify space-separated folder/file paths which point to the Python files
+  that implement QML classes. By default, the parent directory of the QML file supplied to
+  ``pyside6-qml`` is searched recursively for all Python files and they are imported. Otherwise,
+  only the paths given in module paths are searched.
+
+* **--verbose/-v**: Run ``pyside6-qml`` in verbose mode. When run in this mode, pyside6-qml prints
+  log messages during various stages of processing.
+
+Options that align with `QML <qml_runtime>`_ runtime utility
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* **--app-typ/-a**: Specifies which application class to use. It takes one of the three values -
+  ``core, gui, widget``. The default value is *gui*.
+
+* **--config/-c**: Load the given built-in configuration. It takes one of two values - ``default,
+  resizeToItem``. This option is only relevant for a QtQuick application. If ``default`` is used,
+  the view resizes to the size of the root item in the QML. If ``resizeToItem`` is used, the view
+  automatically resizes the root item to the size of the view.
+
+* **--list-conf**: List the built-in configurations. ``pyside6-qml`` has two built-in configurations
+  - ``default`` and ``resizeToItem``. See the option ``--config`` for more information.
+
+* **--rhi/-r**: Specifies the backend for the Qt graphics abstraction (RHI). It takes one of the
+  four values - ``vulkan, metal, d3dll, gl``.
+
+* **--verbose/-v**: List the built-in configurations. ``pyside6-qml`` has two built-in
+  configurations - *default* and *resizeToItem*. See the option ``--config`` for more information.
+
+* **--gles**: Force use of GLES (AA_UseOpenGLES).
+
+* **--desktop**: Force use of desktop OpenGL (AA_UseDesktopOpenGL).
+
+* **--software**: Force use of software rendering(AA_UseSoftwareOpenGL).
+
+* **--disable-context-sharing**: Disable the use of a shared GL context for QtQuick Windows".
+
+.. _`qml_runtime`: https://doc.qt.io/qt-6/qtquick-qml-runtime.html
+.. _`qqmlappengine`: https://doc.qt.io/qt-6/qqmlapplicationengine.html
+.. _`qquickview`: https://doc.qt.io/qt-6/qquickview.html
+.. _`extending_qml_example`: https://doc.qt.io/qtforpython-6/examples/example_qml_tutorials_extending-qml_chapter6-plugins.html
diff --git a/sources/pyside6/doc/tools/pyside-qmlcachegen.rst b/sources/pyside6/doc/tools/pyside-qmlcachegen.rst
new file mode 100644 (file)
index 0000000..ecd8e6a
--- /dev/null
@@ -0,0 +1,25 @@
+.. _pyside6-qmlcachegen:
+
+pyside6-qmlcachegen
+===================
+
+``pyside6-qmlcachegen`` is a command line tool that wraps `qmlcachegen`_.
+This tool creates C++ code or `QML byte code` for ``.qml`` files. For
+Qt for Python, only `QML byte code` is relevant. The file suffix is
+``.qmlc`` and it works similar to compiled Python bytecode
+(``.pyc`` files).
+
+Usage
+-----
+
+The command line option ``--only-bytecode`` should be used to
+create `QML byte code`. For example:
+
+.. code-block:: bash
+
+    qmlcachegen --only-bytecode gallery.qml
+
+produces a file ``gallery.qmlc`` containing `QML byte code` which is
+automatically loaded by the QML engine.
+
+.. _`qmlcachegen`: https://doc.qt.io/qt-6/qtqml-tool-qmlcachegen.html
diff --git a/sources/pyside6/doc/tools/pyside-qmllint.rst b/sources/pyside6/doc/tools/pyside-qmllint.rst
new file mode 100644 (file)
index 0000000..54a7247
--- /dev/null
@@ -0,0 +1,49 @@
+.. _pyside6-qmllint:
+
+pyside6-qmllint
+===============
+
+``pyside6-qmllint`` is a command line tool that wraps `qmllint`_. This tool
+verifies the syntatic validity of QML files and warns about some QML
+anti-patterns.
+
+It is automatically run by the :ref:`pyside6-project` tool
+when passing the ``qmllint`` argument instructing it to check
+the QML source files.
+
+Usage
+-----
+
+The tool should normally not be invoked manually since it requires
+a number of import paths and additional type information
+generated by :ref:`pyside6-qmltyperegistrar` to function.
+
+For example, for a ``.qml`` file like:
+
+.. code-block:: javascript
+
+    import QtQuick
+    import QtQuick.Controls
+
+    Item {
+        Text {
+            id: name
+            text: qsTr("Hello World")
+        }
+    }
+
+when running:
+
+.. code-block:: bash
+
+    pyside6-qmllint Main.qml
+
+it would warn about unused imports:
+
+.. code-block::
+
+    Info: Main.qml:2:1: Unused import [unused-imports]
+    import QtQuick.Controls
+    ^^^^^^
+
+.. _`qmllint`: https://doc.qt.io/qt-6/qtquick-tool-qmllint.html
diff --git a/sources/pyside6/doc/tools/pyside-qmltyperegistrar.rst b/sources/pyside6/doc/tools/pyside-qmltyperegistrar.rst
new file mode 100644 (file)
index 0000000..0e8d66b
--- /dev/null
@@ -0,0 +1,17 @@
+.. _pyside6-qmltyperegistrar:
+
+pyside6-qmltyperegistrar
+========================
+
+``pyside6-qmltyperegistrar`` is a command line tool that wraps the
+``qmltyperegistrar`` tool of Qt.
+
+It takes the file produced by :ref:`pyside6-metaobjectdump`
+as input and generates C++ code to register C++ classes to QML
+and a ``.qmltypes`` file containing a JSON description of the
+classes. For Qt for Python, only the ``.qmltypes`` file
+is of interest as input for :ref:`pyside6-qmllint`.
+
+The tool is automatically run by the :ref:`pyside6-project` tool
+when passing the ``qmllint`` argument instructing it to check
+the QML source files.
diff --git a/sources/pyside6/doc/tools/pyside-rcc.rst b/sources/pyside6/doc/tools/pyside-rcc.rst
new file mode 100644 (file)
index 0000000..e568848
--- /dev/null
@@ -0,0 +1,55 @@
+.. _pyside6-rcc:
+
+pyside6-rcc
+===========
+
+.. note:: This tool is automatically called by :ref:`pyside6-project`
+   so you don't need to call it manually. *Qt Creator* will take care
+   of this step as well while executing a project.
+
+
+``pyside6-rcc`` is a command line tool for converting ``.qrc`` files into ``.py``
+files, so they can be used within your Python code.
+
+The tool is a wrapper around the `rcc`_ tool, which was originally
+designed to generate C++ code, but it also has Python support.
+
+Even though the equivalent of ``pyside6-rcc`` is running ``rcc -g python``
+we strongly recommend you to rely on ``pyside6-rcc`` in order to avoid
+mismatches between versions for the generated code.
+
+Usage
+-----
+
+Once you have gathered your resources on a qrc file,
+you can transform your ``.qrc`` file with the following command:
+
+.. code-block:: bash
+
+    pyside6-rcc your_file.qrc -o rc_your_file.py
+
+It is important to use the ``-o`` option to generate the Python file with the
+conversion, otherwise you will receive all the output as stdout in your terminal.
+
+To enable the usage of those resources in your program, you need to import
+the file:
+
+.. code-block:: Python
+
+    import rc_your_file
+
+then you can use a specific resource, for example an image, with the prefix ``:/``,
+for example:
+
+.. code-block:: Python
+
+    pixmap = QPixmap(":/icons/image.png")
+
+
+For additional options, you can use ``pyside6-rcc -h`` in order to get
+more information about additional options.
+
+Visit the tutorial :ref:`using_qrc_files` for a hands-on example.
+
+.. _`rcc`: https://doc.qt.io/qt-6/rcc.html
+
diff --git a/sources/pyside6/doc/tools/pyside-uic.rst b/sources/pyside6/doc/tools/pyside-uic.rst
new file mode 100644 (file)
index 0000000..ba4e36b
--- /dev/null
@@ -0,0 +1,59 @@
+.. _pyside6-uic:
+
+pyside6-uic
+===========
+
+.. note:: This tool is automatically called by :ref:`pyside6-project`
+   so you don't need to call it manually. *Qt Creator* will take care
+   of this step as well while executing a project.
+
+``pyside6-uic`` is a command line tool for converting ``.ui`` files into ``.py``
+files, with the objective of using application designs as Python classes.
+
+The tool is a wrapper around the `uic`_ tool, which was originally
+designed to generate C++ code, but it also has Python support.
+
+Even though the equivalent of ``pyside6-uic`` is running ``uic -g python``
+we strongly recommend you to rely on ``pyside6-uic`` in order to avoid
+mismatches between versions for the generated code.
+
+Usage
+-----
+
+Once you have designed your application with :ref:`pyside6-designer`,
+you can transform your ``.ui`` file with the following command:
+
+.. code-block:: bash
+
+    pyside6-uic your_file.ui -o ui_your_file.py
+
+It is important to use the ``-o`` option to generate the Python file with the
+conversion, otherwise you will receive all the output as stdout in your terminal.
+
+The structure of the generated Python file will be similar in all cases,
+and you will get one class called ``Ui_TheNameOfYourDesign(object)`` that
+is in charge of positioning all the elements like your design.
+
+To use this Python file, you should follow our tutorial in
+:ref:`using_ui_files`, but in summary, it is mainly importing the class
+from the generated file and setting it up in your code:
+
+.. code-block:: Python
+
+    self.ui = Ui_TheNameOfYourDesign()
+    self.ui.setupUi(self)
+
+For additional options, you can use ``pyside-uic -h`` in order to get
+more information related to relative imports, absolute imports, using resources,
+translations, etc.
+
+.. note:: Remember that you need to have a class corresponding to the base
+    form you selected in :ref:`pyside6-designer`, a ``QWidget``, or ``QDialog``,
+    or ``QMainWindow``, etc, in order for ``setupUi`` to work. Check
+    :ref:`using_ui_files` for more information.
+
+.. warning:: Do not modify the content of the generated Python file from your
+    ``.ui`` file, otherwise everything will be lost when you re-generate it.
+
+.. _`uic`: https://doc.qt.io/qt-6/uic.html
+
diff --git a/sources/pyside6/doc/tools/pyside6-assistant_screenshot.webp b/sources/pyside6/doc/tools/pyside6-assistant_screenshot.webp
new file mode 100644 (file)
index 0000000..7d898d8
Binary files /dev/null and b/sources/pyside6/doc/tools/pyside6-assistant_screenshot.webp differ
diff --git a/sources/pyside6/doc/tools/pyside6-balsam.rst b/sources/pyside6/doc/tools/pyside6-balsam.rst
new file mode 100644 (file)
index 0000000..c6677f6
--- /dev/null
@@ -0,0 +1,59 @@
+.. _pyside6-balsam:
+
+pyside6-balsam
+==============
+
+``pyside6-qsb`` is a tool that wraps the `balsam <Balsam Asset Import Tool>`_
+tool provided with Qt Quick 3D. The Balsam tool is a command line application
+that is part of Qt Quick 3D's asset conditioning pipeline. The purpose is to
+take assets created in digital content creation tools like `Maya`_, `3ds Max`_
+or `Blender`_ and converts them into an efficient runtime format for use with Qt
+Quick 3D. It is not possible, nor does it make sense to reference the
+interchange formats directly in applications because a large amount of
+resources are needed to parse and condition the content of the asset before it
+is usable for real-time rendering. Instead, the interchange formats can be
+converted via the Balsam tool into QML Components and resources like geometry
+and textures.
+
+
+For more information on how to use this tool, read Qt's documentation
+here: `Balsam Asset Import Tool`_.
+
+Usage
+-----
+
+.. code-block:: bash
+
+    pyside6-balsam [options] sourceFileName
+
+To convert a 3D asset contained in the file ``testModel.fbx`` with
+``pyside6-balsam`` the following command would be used:
+
+.. code-block:: bash
+
+    pyside6-balsam testModel.fbx
+
+This would generate the following files:
+
+* meshes/testModel.mesh
+* TestModel.qml
+
+Which can then be used in a Qt Quick 3D project by using that QML Component:
+
+.. code-block:: xml
+
+    import QtQuick3D 1.0
+
+    Scene {
+        Model {
+            source: "TestModel.qml"
+        }
+    }
+
+For other modes of operation, refer to the `Balsam Asset Import Tool`_.
+
+.. _`Balsam Asset Import Tool`: https://doc.qt.io/qt-6/qtquick3d-tool-balsam.html
+.. _Maya: https://www.autodesk.com/products/maya/overview
+.. _3ds Max: https://www.autodesk.com/products/3ds-max/overview
+.. _Blender: https://www.blender.org/
+
diff --git a/sources/pyside6/doc/tools/pyside6-balsamui.rst b/sources/pyside6/doc/tools/pyside6-balsamui.rst
new file mode 100644 (file)
index 0000000..f34cb60
--- /dev/null
@@ -0,0 +1,22 @@
+.. _pyside6-balsamui:
+
+pyside6-balsamui
+================
+
+``pyside6-balsamui`` is graphical user interface frontend to the command line
+tool :ref:`pyside6-balsam`. The purpose of the tool is to take assets created
+in digital content creation tools like `Maya`_, `3ds Max`_ or `Blender`_ and
+converts them into an efficient runtime format for use with Qt Quick 3D.
+
+For more information on the further capabilities of the tool, read Qt's
+documentation here: `Balsam Asset Import Tool`_.
+
+.. image:: pyside6-balsamui_screenshot.webp
+    :width: 500
+    :alt: pyside6-balsamui screenshot
+
+.. _`Balsam Asset Import Tool`: https://doc.qt.io/qt-6/qtquick3d-tool-balsam.html
+.. _Maya: https://www.autodesk.com/products/maya/overview
+.. _3ds Max: https://www.autodesk.com/products/3ds-max/overview
+.. _Blender: https://www.blender.org/
+
diff --git a/sources/pyside6/doc/tools/pyside6-balsamui_screenshot.webp b/sources/pyside6/doc/tools/pyside6-balsamui_screenshot.webp
new file mode 100644 (file)
index 0000000..5c194fd
Binary files /dev/null and b/sources/pyside6/doc/tools/pyside6-balsamui_screenshot.webp differ
diff --git a/sources/pyside6/doc/tools/pyside6-designer_base_screenshot.webp b/sources/pyside6/doc/tools/pyside6-designer_base_screenshot.webp
new file mode 100644 (file)
index 0000000..88ff777
Binary files /dev/null and b/sources/pyside6/doc/tools/pyside6-designer_base_screenshot.webp differ
diff --git a/sources/pyside6/doc/tools/pyside6-designer_customwidgets_screenshot.webp b/sources/pyside6/doc/tools/pyside6-designer_customwidgets_screenshot.webp
new file mode 100644 (file)
index 0000000..c84436c
Binary files /dev/null and b/sources/pyside6/doc/tools/pyside6-designer_customwidgets_screenshot.webp differ
diff --git a/sources/pyside6/doc/tools/pyside6-designer_screenshot.webp b/sources/pyside6/doc/tools/pyside6-designer_screenshot.webp
new file mode 100644 (file)
index 0000000..27f0365
Binary files /dev/null and b/sources/pyside6/doc/tools/pyside6-designer_screenshot.webp differ
diff --git a/sources/pyside6/doc/tools/pyside6-designer_sections_screenshot.webp b/sources/pyside6/doc/tools/pyside6-designer_sections_screenshot.webp
new file mode 100644 (file)
index 0000000..6ff0255
Binary files /dev/null and b/sources/pyside6/doc/tools/pyside6-designer_sections_screenshot.webp differ
diff --git a/sources/pyside6/doc/tools/pyside6-linguist_screenshot.webp b/sources/pyside6/doc/tools/pyside6-linguist_screenshot.webp
new file mode 100644 (file)
index 0000000..cd91007
Binary files /dev/null and b/sources/pyside6/doc/tools/pyside6-linguist_screenshot.webp differ
diff --git a/sources/pyside6/doc/tools/pyside6-qmlimportscanner.rst b/sources/pyside6/doc/tools/pyside6-qmlimportscanner.rst
new file mode 100644 (file)
index 0000000..ba27414
--- /dev/null
@@ -0,0 +1,53 @@
+.. _pyside6-qmlimportscanner:
+
+pyside6-qmlimportscanner
+========================
+
+``pyside6-qmlimportscanner`` is a command line tool that wraps the
+``qmlimportscanner`` tool of Qt.
+
+
+The tool is automatically run by the :ref:`pyside6-project` tool
+when passing the ``qmllint`` argument instructing it to check
+the QML source files.
+
+Usage
+-----
+
+Invoking the tool in the directory of the :ref:`filesystemexplorer_example`
+example using:
+
+.. code-block:: bash
+
+    pyside6-qmlimportscanner -rootPath .
+
+produces:
+
+.. code-block:: json
+
+    [
+        {
+            "name": "QtQuick",
+            "type": "module"
+        },
+        {
+            "name": "QtQuick.Controls.Basic",
+            "type": "module"
+        },
+        {
+            "name": "QtQuick.Layouts",
+            "type": "module"
+        },
+        {
+            "name": "FileSystemModule",
+            "type": "module"
+        },
+        {
+            "name": "QtQuick.Controls",
+            "type": "module"
+        },
+        {
+            "name": "QtQuick.Effects",
+            "type": "module"
+        }
+    ]
diff --git a/sources/pyside6/doc/tools/pyside6-qsb.rst b/sources/pyside6/doc/tools/pyside6-qsb.rst
new file mode 100644 (file)
index 0000000..f6f1847
--- /dev/null
@@ -0,0 +1,39 @@
+.. _pyside6-qsb:
+
+pyside6-qsb
+===========
+
+``pyside6-qsb`` is a tool that wraps the `qsb <QSB Manual>`_ tool. qsb is a
+command line tool provided by the `Qt Shader Tools`_ module. It integrates
+third-party libraries such as `glslang`_ and `SPIRV-Cross`_, optionally invokes
+external tools, such as ``fxc`` or ``spirv-opt``, and generates .qsb files.
+Additionally, it can be used to inspect the contents of a .qsb package.
+
+For more information on how to use this tool, read Qt's documentation
+here: `QSB Manual`_.
+
+Usage
+-----
+
+To create a qsb file from a shader file, e.g., ``shader.frag``, use the
+following command:
+
+.. code-block:: bash
+
+    pyside6-qsb -o shader.frag.qsb shader.frag
+
+To inspect the file produced, i.e., ``shader.frag.qsb``, use the following
+command:
+
+.. code-block:: bash
+
+    pyside6-qsb -d shader.frag.qsb
+
+This will print the reflection metadata (in JSON form) and the included shaders.
+
+For other modes of operation, refer to the `QSB Manual`_.
+
+.. _`glslang`: https://github.com/KhronosGroup/glslang
+.. _`spirv-cross`: https://github.com/KhronosGroup/SPIRV-Cross
+.. _`QSB Manual`: https://doc.qt.io/qt-6/qtshadertools-qsb.html
+.. _`Qt Shader Tools`: https://doc.qt.io/qt-6/qtshadertools-index.html
index 21f4e1e2b096f49bd19438a3dd0c7676b3b89402..858293beb6e9ab246e77817bdaf2ded6ad62442d 100644 (file)
@@ -46,7 +46,6 @@ In the following example, notice how the resources are listed in ``icons.qrc``
 
 ::
 
-    </ui>
     <!DOCTYPE RCC><RCC version="1.0">
     <qresource>
         <file>icons/play.png</file>
index 9c216da6db956373533d1b1fdb581708ed6f3087..0bfd9e2768a7fce7c6a3dff8ca7f2d05b71f7b3d 100644 (file)
@@ -79,7 +79,7 @@ Signals can also be connected to free functions:
 Connections can be spelled out in code or, for widget forms,
 designed in the
 `Signal-Slot Editor <https://doc.qt.io/qt-6/designer-connection-mode.html>`_
-of Qt Designer.
+of *Qt Widgets Designer*.
 
 The Signal Class
 ----------------
@@ -139,6 +139,9 @@ useful for QML applications to refer to the emitted values by name:
             // do something with 'sum'
         }
 
+
+.. _slot-decorator:
+
 The Slot Class
 --------------
 
@@ -223,6 +226,8 @@ the different functionality.
         someone.speak[str].emit("Hello everybody!")
 
 
+.. _signals-and-slots-strings:
+
 Specifying Signals and Slots by Method Signature Strings
 --------------------------------------------------------
 
@@ -235,12 +240,24 @@ strings passed through the ``SIGNAL()`` and/or ``SLOT()`` functions:
     from PySide6.QtCore import SIGNAL, SLOT
 
     button.connect(SIGNAL("clicked(Qt::MouseButton)"),
-                  action_handler, SLOT("action1(Qt::MouseButton)"))
+                   action_handler, SLOT("action1(Qt::MouseButton)"))
 
-This is not recommended for connecting signals, it is mostly
-used to specify signals for methods like ``QWizardPage::registerField()``:
+This is not normally recommended; it is only needed
+for a few cases where signals are only accessible via ``QMetaObject``
+(``QAxObject``, ``QAxWidget``, ``QDBusInterface`` or ``QWizardPage::registerField()``):
 
 .. code-block:: python
 
     wizard.registerField("text", line_edit, "text",
                          SIGNAL("textChanged(QString)"))
+
+The signature strings can be found by querying ``QMetaMethod.methodSignature()``
+when introspecting ``QMetaObject``:
+
+.. code-block:: python
+
+    mo = widget.metaObject()
+    for m in range(mo.methodOffset(), mo.methodCount()):
+        print(mo.method(m).methodSignature())
+
+Slots should be decorated using :ref:`@Slot <slot-decorator>`.
index 6ca403ba7b1e2e33f24cea717b89b9d0c5e2bd22..21c16cdcdc5cce88e69aab33df1ba09010223d9b 100644 (file)
@@ -54,13 +54,27 @@ they should be passed to the ``pyside6-lupdate`` tool as well:
 The source files generated by ``pyside6-uic`` from the form files
 should **not** be passed.
 
+The ``lupdate`` mode of ``pyside6-project`` can also be used for this. It
+collects all source files and runs ``pyside6-lupdate`` when ``.ts`` file(s)
+are given in the ``.pyproject`` file:
+
+.. code-block:: bash
+
+    pyside6-project lupdate .
+
 ``.ts`` files are translated using *Qt Linguist*. Once this is complete,
 the files are converted to a binary form (``.qm`` files):
 
 .. code-block:: bash
 
-    mkdir translations
-    pyside6-lrelease example_de.ts -qm translations/example_de.qm
+    pyside6-lrelease example_de.ts -qm example_de.qm
+
+``pyside6-project`` will build the ``.qm`` file automatically when
+``.ts`` file(s) are given in the ``.pyproject`` file:
+
+.. code-block:: bash
+
+    pyside6-project build .
 
 To avoid having to ship the ``.qm`` files, it is recommend
 to put them into a Qt resource file along with icons and other
@@ -71,8 +85,8 @@ under ``:/translations``:
 .. code-block:: xml
 
     <!DOCTYPE RCC><RCC version="1.0">
-    <qresource>
-        <file>translations/example_de.qm</file>
+    <qresource prefix="translations">
+        <file>example_de.qm</file>
     </qresource>
     </RCC>
 
index c56593ee4e0d17fa75505ef95b444a42652a5343..cb945908d186906eaa0945c75c3ce3d1e6a44490 100644 (file)
@@ -4,13 +4,13 @@ Using ``.ui`` files from Designer or QtCreator with ``QUiLoader`` and ``pyside6-
 *************************************************************************************
 
 This page describes the use of
-`Qt Designer <https://doc.qt.io/qt-6/qtdesigner-manual.html>`_ to create
+`Qt Widgets Designer <https://doc.qt.io/qt-6/qtdesigner-manual.html>`_ to create
 graphical interfaces based on Qt Widgets for your Qt for Python project.
-**Qt Designer** is a graphical UI design tool which is available as a
+*Qt Widgets Designer* is a graphical UI design tool which is available as a
 standalone binary (``pyside6-designer``) or embedded into the
-`Qt Creator IDE <https://doc.qt.io/qtcreator>`_. Its use within **Qt Creator**
+`Qt Creator IDE <https://doc.qt.io/qtcreator>`_. Its use within *Qt Creator*
 is described at
-`Using Qt Designer <https://doc.qt.io/qtcreator/creator-using-qt-designer.html>`_.
+`Using Qt Widgets Designer <https://doc.qt.io/qtcreator/creator-using-qt-designer.html>`_.
 
 .. image:: uifiles.png
    :alt: Designer and the equivalent code
@@ -19,7 +19,7 @@ The designs are stored in ``.ui`` files, which is an XML-based format. It will
 be converted to Python or C++ code populating a widget instance at project build
 time by the `pyside6-uic <https://doc.qt.io/qt-6/uic.html>`_ tool.
 
-To create a new Qt Design Form in **Qt Creator**, choose
+To create a new Qt Design Form in *Qt Creator*, choose
 ``File/New File Or Project`` and "Main Window" for template. Save it as
 ``mainwindow.ui``. Add a ``QPushButton`` to the center of the centralwidget.
 
@@ -206,24 +206,25 @@ command prompt:
 
 .. _designer_custom_widgets:
 
-Custom Widgets in Qt Designer
-=============================
+Custom Widgets in Qt Widgets Designer
+=====================================
 
-**Qt Designer** is able to use user-provided (custom) widgets. They are shown
-in the widget box and can be dragged onto the form just like Qt's widgets (see
-`Using Custom Widgets with Qt Designer <https://doc.qt.io/qt-6/designer-using-custom-widgets.html>`_
-). Normally, this requires implementing the widget as a plugin to Qt Designer
-written in C++ implementing its
+*Qt Widgets Designer* is able to use user-provided (custom) widgets.
+They are shown in the widget box and can be dragged onto the form just like
+Qt's widgets (see
+`Using Custom Widgets with Qt Widgets Designer <https://doc.qt.io/qt-6/designer-using-custom-widgets.html>`_
+). Normally, this requires implementing the widget as a plugin to
+*Qt Widgets Designer* written in C++ implementing its
 `QDesignerCustomWidgetInterface`_ .
 
 Qt for Python provides a simple interface for this which is similar to
 :meth:`registerCustomWidget()<PySide6.QtUiTools.QUiLoader.registerCustomWidget>`.
 
 The widget needs to be provided as a Python module, as shown by
-the widgetbinding example (file ``wigglywidget.py``) or
-the taskmenuextension example (file ``tictactoe.py``).
+the :ref:`widgetbinding-example` (file ``wigglywidget.py``) or
+the :ref:`task-menu-extension-example` (file ``tictactoe.py``).
 
-Registering this with Qt Designer is done by providing
+Registering this with *Qt Widgets Designer* is done by providing
 a registration script named ``register*.py`` and pointing
 the path-type environment variable ``PYSIDE_DESIGNER_PLUGINS``
 to the directory.
@@ -263,19 +264,19 @@ The code of the registration script looks as follows:
 
 QPyDesignerCustomWidgetCollection provides an implementation of
 `QDesignerCustomWidgetCollectionInterface`_
-exposing custom widgets to **Qt Designer** with static convenience functions
-for registering types or adding instances of
+exposing custom widgets to *Qt Widgets Designer* with static convenience
+functions for registering types or adding instances of
 `QDesignerCustomWidgetInterface`_ .
 
 The function
 :meth:`registerCustomWidget()<PySide6.QtDesigner.QPyDesignerCustomWidgetCollection.registerCustomWidget>`
-is used to register a widget type with **Qt Designer**. In the simple case, it
+is used to register a widget type with *Qt Widgets Designer*. In the simple case, it
 can be used like ``QUiLoader.registerCustomWidget()``. It takes the custom widget
 type and some optional keyword arguments passing values that correspond to the
 getters of
 `QDesignerCustomWidgetInterface`_ :
 
-When launching **Qt Designer** via its launcher ``pyside6-designer``,
+When launching *Qt Widgets Designer* via its launcher ``pyside6-designer``,
 the custom widget should be visible in the widget box.
 
 For advanced usage, it is also possible to pass the function an implementation
@@ -289,15 +290,15 @@ corresponding C++
 .. _QDesignerCustomWidgetCollectionInterface: https://doc.qt.io/qt-6/qdesignercustomwidgetcollectioninterface.html
 .. _QDesignerCustomWidgetInterface: https://doc.qt.io/qt-6/qdesignercustomwidgetinterface.html
 
-Troubleshooting the Qt Designer Plugin
-++++++++++++++++++++++++++++++++++++++
+Troubleshooting the Qt Widgets Designer Plugin
+++++++++++++++++++++++++++++++++++++++++++++++
 
 - The launcher ``pyside6-designer`` must be used. The standalone
-  **Qt Designer** will not load the plugin.
+  *Qt Widgets Designer* will not load the plugin.
 - The menu item **Help/About Plugin** brings up a dialog showing the plugins
   found and potential load error messages.
 - Check the console or Windows Debug view for further error messages.
 - Due to the buffering of output by Python, error messages may appear
-  only after **Qt Designer** has terminated.
+  only after *Qt Widgets Designer* has terminated.
 - When building Qt for Python, be sure to set the ``--standalone`` option
   for the plugin to be properly installed.
index d425b701f2397fc3f21ace3736cf8b24a3b73369..85c32634708257f4b7128e55923b46c024f786e7 100644 (file)
@@ -5,10 +5,10 @@ When debugging PySide code, very often you would also like to debug the
 corresponding C++ extension of the PySide module. This is done by attaching your
 debugger to the Python interpreter. In this tutorial, we are going to take you
 through a comprehensive guide in building Qt 6, using the built Qt 6 to build
-PySide6, and then starting a debugging process in either Qt Creator or VSCode.
+PySide6, and then starting a debugging process in either *Qt Creator* or VSCode.
 
 With VSCode, you should be able to see the combined call stacks for both C++ and
-Python together. With Qt Creator, unfortunately you would only be able to
+Python together. With *Qt Creator*, unfortunately you would only be able to
 debug the native C++ code of the PySide module; that is you won't be able to set
 breakpoints inside the Python code.
 
@@ -116,7 +116,7 @@ It is recommended to use a Python virtual environment rather than installing in
 Debugging the process using your preferred IDE
 ----------------------------------------------
 
-The following sections guide you through the setup for Qt Creator or VSCode.
+The following sections guide you through the setup for *Qt Creator* or VSCode.
 
 .. toctree::
    :glob:
index 474abe50b0c2ded81e0c7a2b4fa347ac9157669e..223e608fc278b5e3e41b82ace4148f205c85574e 100644 (file)
@@ -1,7 +1,7 @@
 Using Qt Creator's QML Debugger for a PySide6 QML Application
 *************************************************************
 
-Besides the C++ debugger, Qt Creator provides a `QML debugger`_ which lets you
+Besides the C++ debugger, *Qt Creator* provides a `QML debugger`_ which lets you
 inspect JavaScript code. It works by connecting to a socket server run by the
 ``QmlEngine`` instance. The port is passed on the command line. To enable it,
 add the below code to your QML application:
index a35020fd13a44cab1b167da6377087b5b5b5fdb5..a78a67fad7a75b1e561311ae8afe6798c3711d00 100644 (file)
@@ -1,9 +1,9 @@
 Debugging PySide with Qt Creator (Linux)
 ****************************************
 
-As opposed to VSCode, presently Qt Creator does not support mixed mode debugging.
+As opposed to VSCode, presently *Qt Creator* does not support mixed mode debugging.
 However, we can debug the C++ implementation of the corresponding Python PySide
-code. Unlike VSCode, Qt Creator provides a very easy interface to attach GDB to
+code. Unlike VSCode, *Qt Creator* provides a very easy interface to attach GDB to
 the Python interpreter. It saves you from doing all the extra configuration
 steps, that have to be done with VSCode.
 
index b699720dd6dd5f728b9d3396d2412a287aa57a53..faa9175d6b1a4b0c65fbf6cb23018a76bd4952fa 100644 (file)
@@ -6,46 +6,68 @@ import QtQuick.Controls.Basic
 import QtQuick.Layouts
 import FileSystemModule
 
+pragma ComponentBehavior: Bound
+
 ApplicationWindow {
     id: root
+
+    property bool expandPath: false
+    property bool showLineNumbers: true
+    property string currentFilePath: ""
+
     width: 1100
     height: 600
+    minimumWidth: 200
+    minimumHeight: 100
     visible: true
+    color: Colors.background
     flags: Qt.Window | Qt.FramelessWindowHint
-    title: qsTr("Qt Quick Controls - File System Explorer")
+    title: qsTr("File System Explorer Example")
 
-    property string currentFilePath: ""
-    property bool expandPath: false
+    function getInfoText() : string {
+        let out = root.currentFilePath
+        if (!out)
+            return qsTr("File System Explorer")
+        return root.expandPath ? out : out.substring(out.lastIndexOf("/") + 1, out.length)
+    }
 
     menuBar: MyMenuBar {
-        rootWindow: root
-
-        infoText: currentFilePath
-            ? (expandPath ? currentFilePath
-            : currentFilePath.substring(currentFilePath.lastIndexOf("/") + 1, currentFilePath.length))
-            : "File System Explorer"
-
+        dragWindow: root
+        infoText: root.getInfoText()
         MyMenu {
             title: qsTr("File")
 
             Action {
                 text: qsTr("Increase Font")
-                shortcut: "Ctrl++"
-                onTriggered: textArea.font.pixelSize += 1
+                shortcut: StandardKey.ZoomIn
+                onTriggered: editor.text.font.pixelSize += 1
             }
             Action {
                 text: qsTr("Decrease Font")
-                shortcut: "Ctrl+-"
-                onTriggered: textArea.font.pixelSize -= 1
+                shortcut: StandardKey.ZoomOut
+                onTriggered: editor.text.font.pixelSize -= 1
             }
             Action {
-                text: expandPath ? qsTr("Toggle Short Path") : qsTr("Toggle Expand Path")
-                enabled: currentFilePath
-                onTriggered: expandPath = !expandPath
+                text: root.showLineNumbers ? qsTr("Toggle Line Numbers OFF")
+                                           : qsTr("Toggle Line Numbers ON")
+                shortcut: "Ctrl+L"
+                onTriggered: root.showLineNumbers = !root.showLineNumbers
+            }
+            Action {
+                text: root.expandPath ? qsTr("Toggle Short Path")
+                                      : qsTr("Toggle Expand Path")
+                enabled: root.currentFilePath
+                onTriggered: root.expandPath = !root.expandPath
+            }
+            Action {
+                text: qsTr("Reset Filesystem")
+                enabled: sidebar.currentTabIndex === 1
+                onTriggered: fileSystemView.rootIndex = undefined
             }
             Action {
                 text: qsTr("Exit")
                 onTriggered: Qt.exit(0)
+                shortcut: StandardKey.Quit
             }
         }
 
@@ -55,149 +77,120 @@ ApplicationWindow {
             Action {
                 text: qsTr("Cut")
                 shortcut: StandardKey.Cut
-                enabled: textArea.selectedText.length > 0
-                onTriggered: textArea.cut()
+                enabled: editor.text.selectedText.length > 0
+                onTriggered: editor.text.cut()
             }
             Action {
                 text: qsTr("Copy")
                 shortcut: StandardKey.Copy
-                enabled: textArea.selectedText.length > 0
-                onTriggered: textArea.copy()
+                enabled: editor.text.selectedText.length > 0
+                onTriggered: editor.text.copy()
             }
             Action {
                 text: qsTr("Paste")
                 shortcut: StandardKey.Paste
-                enabled: textArea.canPaste
-                onTriggered: textArea.paste()
+                enabled: editor.text.canPaste
+                onTriggered: editor.text.paste()
             }
             Action {
                 text: qsTr("Select All")
                 shortcut: StandardKey.SelectAll
-                enabled: textArea.length > 0
-                onTriggered: textArea.selectAll()
+                enabled: editor.text.length > 0
+                onTriggered: editor.text.selectAll()
             }
             Action {
                 text: qsTr("Undo")
                 shortcut: StandardKey.Undo
-                enabled: textArea.canUndo
-                onTriggered: textArea.undo()
+                enabled: editor.text.canUndo
+                onTriggered: editor.text.undo()
             }
         }
     }
-
-    Rectangle {
+    // Set up the layout of the main components in a row:
+    // [ Sidebar, Navigation, Editor ]
+    RowLayout {
         anchors.fill: parent
-        color: Colors.background
-
-        RowLayout {
-            anchors.fill: parent
-            spacing: 0
-
-            // Stores the buttons that navigate the application.
-            Sidebar {
-                id: sidebar
-                z: 2
-                rootWindow: root
-
-                Layout.preferredWidth: 60
-                Layout.fillHeight: true
-            }
+        spacing: 0
+
+        // Stores the buttons that navigate the application.
+        Sidebar {
+            id: sidebar
+            dragWindow: root
+            Layout.preferredWidth: 50
+            Layout.fillHeight: true
+        }
 
-            // Allows resizing parts of the UI.
-            SplitView {
-                Layout.fillWidth: true
-                Layout.fillHeight: true
-
-                handle: Rectangle {
-                    implicitWidth: 10
-                    color: SplitHandle.pressed ? Colors.color2 : Colors.background
-                    border.color: Colors.color2
-                    opacity: SplitHandle.hovered || SplitHandle.pressed ? 1.0 : 0.0
-
-                    Behavior on opacity {
-                        OpacityAnimator {
-                            duration: 900
-                        }
+        // Allows resizing parts of the UI.
+        SplitView {
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+            // Customized handle to drag between the Navigation and the Editor.
+            handle: Rectangle {
+                implicitWidth: 10
+                color: SplitHandle.pressed ? Colors.color2 : Colors.background
+                border.color: SplitHandle.hovered ? Colors.color2 : Colors.background
+                opacity: SplitHandle.hovered || navigationView.width < 15 ? 1.0 : 0.0
+
+                Behavior on opacity {
+                    OpacityAnimator {
+                        duration: 1400
                     }
                 }
+            }
 
-                // We use an inline component to make a reusable TextArea component.
-                // This is convenient when the component is only used in one file.
-                component MyTextArea: TextArea {
-                    antialiasing: true
-                    color: Colors.textFile
-                    selectedTextColor: Colors.textFile
-                    selectionColor: Colors.selection
-                    renderType: Text.QtRendering
-                    textFormat: TextEdit.PlainText
-
-                    background: null
-                }
-
-                Rectangle {
-                    z: 1
-                    color: Colors.surface1
-
-                    SplitView.preferredWidth: 250
-                    SplitView.fillHeight: true
-
-                    StackLayout {
-                        currentIndex: sidebar.currentTabIndex > 1 ? 1 : sidebar.currentTabIndex
-
-                        anchors.fill: parent
-
-                        // Shows the help text.
-                        MyTextArea {
-                            readOnly: true
-                            text: qsTr("This example shows how to use and visualize the file system.\n\n"
-                                + "Customized Qt Quick Components have been used to achieve this look.\n\n"
-                                + "You can edit the files but they won't be changed on the file system.\n\n"
-                                + "Click on the folder icon to the left to get started.")
-                            wrapMode: TextArea.Wrap
-                        }
-
-                        // Shows the files on the file system.
-                        FileSystemView {
-                            id: fileSystemView
-                            color: Colors.surface1
+            Rectangle {
+                id: navigationView
+                color: Colors.surface1
+                SplitView.preferredWidth: 250
+                SplitView.fillHeight: true
+                // The stack-layout provides different views, based on the
+                // selected buttons inside the sidebar.
+                StackLayout {
+                    anchors.fill: parent
+                    currentIndex: sidebar.currentTabIndex > 1 ? 1 : sidebar.currentTabIndex
+
+                    // Shows the help text.
+                    Text {
+                        text: qsTr("This example shows how to use and visualize the file system.\n\n"
+                                 + "Customized Qt Quick Components have been used to achieve this look.\n\n"
+                                 + "You can edit the files but they won't be changed on the file system.\n\n"
+                                 + "Click on the folder icon to the left to get started.")
+                        wrapMode: TextArea.Wrap
+                        color: Colors.text
+                    }
 
-                            onFileClicked: (path) => root.currentFilePath = path
-                        }
+                    // Shows the files on the file system.
+                    FileSystemView {
+                        id: fileSystemView
+                        color: Colors.surface1
+                        onFileClicked: path => root.currentFilePath = path
                     }
                 }
+            }
 
-                // The ScrollView that contains the TextArea which shows the file's content.
-                StackLayout {
-                    currentIndex: sidebar.currentTabIndex > 1 ? 1 : 0
-
-                    SplitView.fillWidth: true
-                    SplitView.fillHeight: true
-                    // TextArea is the first element inside the stack
-                    ScrollView {
-                        Layout.fillWidth: true
-                        Layout.fillHeight: true
-
-                        leftPadding: 20
-                        topPadding: 20
-                        bottomPadding: 20
+            // The main view that contains the editor or the scheme-manager.
+            StackLayout {
+                currentIndex: sidebar.currentTabIndex > 1 ? 1 : 0
 
-                        clip: true
+                SplitView.fillWidth: true
+                SplitView.fillHeight: true
 
-                        property alias textArea: textArea
+                Editor {
+                    id: editor
+                    showLineNumbers: root.showLineNumbers
+                    currentFilePath: root.currentFilePath
+                }
 
-                        MyTextArea {
-                            id: textArea
-                            text: FileSystemModel.readFile(root.currentFilePath)
-                        }
-                    }
-                    // The ColorScheme is the second element in the stack
-                    ColorScheme {
-                        Layout.fillWidth: true
-                        Layout.fillHeight: true
-                    }
+                ColorScheme {
+                    Layout.fillWidth: true
+                    Layout.fillHeight: true
                 }
+
             }
         }
-        ResizeButton {}
+    }
+
+    ResizeButton {
+        resizeWindow: root
     }
 }
index 7303ced8fce9dced2c55aa0f23338435b1cf1d9c..ccd9eefec5d710a1941d4b1aec0d10e1e75b9036 100644 (file)
@@ -3,7 +3,8 @@
         <file>qmldir</file>
         <file>Main.qml</file>
         <file>qml/About.qml</file>
-        <file>qml/ColorScheme.qml</file>
+        <file>qml/Editor.qml</file>
+        <file>qml/Colors.qml</file>
         <file>qml/FileSystemView.qml</file>
         <file>qml/Icon.qml</file>
         <file>qml/MyMenu.qml</file>
index 61323cef13533cedff98c972a937a28d208f1a6c..69bddc01840e34c164d4802f17238c91910cb5b8 100644 (file)
@@ -1,14 +1,15 @@
 <RCC>
     <qresource>
+        <file>icons/app_icon.svg</file>
         <file>icons/folder_closed.svg</file>
         <file>icons/folder_open.svg</file>
         <file>icons/generic_file.svg</file>
         <file>icons/globe.svg</file>
         <file>icons/info_sign.svg</file>
+        <file>icons/leaf.svg</file>
         <file>icons/light_bulb.svg</file>
         <file>icons/qt_logo.svg</file>
         <file>icons/read.svg</file>
         <file>icons/resize.svg</file>
-        <file>icons/leaf.svg</file>
     </qresource>
 </RCC>
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/app_icon.svg b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/icons/app_icon.svg
new file mode 100644 (file)
index 0000000..5aae422
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill="#EBDBB2" d="M13.25 8.5a.75.75 0 1 1-.75-.75.75.75 0 0 1 .75.75zM9.911 21.35l.816.578C10.819 21.798 13 18.666 13 13h-1a15.503 15.503 0 0 1-2.089 8.35zM4 6.703V10a2.002 2.002 0 0 1-2 2v1a2.002 2.002 0 0 1 2 2v3.297A3.707 3.707 0 0 0 7.703 22H9v-1H7.703A2.706 2.706 0 0 1 5 18.297V15a2.999 2.999 0 0 0-1.344-2.5A2.999 2.999 0 0 0 5 10V6.703A2.706 2.706 0 0 1 7.703 4H9V3H7.703A3.707 3.707 0 0 0 4 6.703zM20 10V6.703A3.707 3.707 0 0 0 16.297 3H15v1h1.297A2.706 2.706 0 0 1 19 6.703V10a2.999 2.999 0 0 0 1.344 2.5A2.999 2.999 0 0 0 19 15v3.297A2.706 2.706 0 0 1 16.297 21H15v1h1.297A3.707 3.707 0 0 0 20 18.297V15a2.002 2.002 0 0 1 2-2v-1a2.002 2.002 0 0 1-2-2z"/><path fill="none" d="M0 0h24v24H0z"/></svg>
index b7bc0ac6f30a40f4796f5637c1aae419d1f84fd9..178bf03e44a0407fa5ba764dcf15d0c99c3ae281 100644 (file)
@@ -7,53 +7,87 @@ import FileSystemModule
 
 ApplicationWindow {
     id: root
-    width: 500
-    height: 360
+    width: 650
+    height: 550
     flags: Qt.Window | Qt.FramelessWindowHint
     color: Colors.surface1
 
     menuBar: MyMenuBar {
         id: menuBar
-        implicitHeight: 20
-        rootWindow: root
+
+        dragWindow: root
+        implicitHeight: 27
         infoText: "About Qt"
     }
 
     Image {
         id: logo
+
         anchors.left: parent.left
         anchors.right: parent.right
         anchors.top: parent.top
         anchors.margins: 20
+
         source: "../icons/qt_logo.svg"
-        sourceSize: Qt.size(80, 80)
+        sourceSize.width: 80
+        sourceSize.height: 80
         fillMode: Image.PreserveAspectFit
+
         smooth: true
         antialiasing: true
         asynchronous: true
     }
 
-    TextArea {
-        anchors.top: logo.bottom
-        anchors.left: parent.left
-        anchors.right: parent.right
-        anchors.bottom: parent.bottom
-        anchors.margins: 20
-        antialiasing: true
-        wrapMode: Text.WrapAnywhere
-        color: Colors.textFile
-        horizontalAlignment: Text.AlignHCenter
-        readOnly: true
-        selectionColor: Colors.selection
-        text: qsTr("Qt Group (Nasdaq Helsinki: QTCOM) is a global software company with a strong \
-presence in more than 70 industries and is the leading independent technology behind 1+ billion \
-devices and applications. Qt is used by major global companies and developers worldwide, and the \
-technology enables its customers to deliver exceptional user experiences and advance their digital \
-transformation initiatives. Qt achieves this through its cross-platform software framework for the \
-development of apps and devices, under both commercial and open-source licenses.")
-        background: Rectangle {
-            color: "transparent"
-        }
+    ScrollView {
+      anchors.top: logo.bottom
+      anchors.left: parent.left
+      anchors.right: parent.right
+      anchors.bottom: parent.bottom
+      anchors.margins: 20
+
+      TextArea {
+          selectedTextColor: Colors.textFile
+          selectionColor: Colors.selection
+          horizontalAlignment: Text.AlignHCenter
+          textFormat: Text.RichText
+
+          text: qsTr("<h3>About Qt</h3>"
+                   + "<p>This program uses Qt version %1.</p>"
+                   + "<p>Qt is a C++ toolkit for cross-platform application "
+                   + "development.</p>"
+                   + "<p>Qt provides single-source portability across all major desktop "
+                   + "operating systems. It is also available for embedded Linux and other "
+                   + "embedded and mobile operating systems.</p>"
+                   + "<p>Qt is available under multiple licensing options designed "
+                   + "to accommodate the needs of our various users.</p>"
+                   + "<p>Qt licensed under our commercial license agreement is appropriate "
+                   + "for development of proprietary/commercial software where you do not "
+                   + "want to share any source code with third parties or otherwise cannot "
+                   + "comply with the terms of GNU (L)GPL.</p>"
+                   + "<p>Qt licensed under GNU (L)GPL is appropriate for the "
+                   + "development of Qt&nbsp;applications provided you can comply with the terms "
+                   + "and conditions of the respective licenses.</p>"
+                   + "<p>Please see <a href=\"http://%2/\">%2</a> "
+                   + "for an overview of Qt licensing.</p>"
+                   + "<p>Copyright (C) %3 The Qt Company Ltd and other "
+                   + "contributors.</p>"
+                   + "<p>Qt and the Qt logo are trademarks of The Qt Company Ltd.</p>"
+                   + "<p>Qt is The Qt Company Ltd product developed as an open source "
+                   + "project. See <a href=\"http://%4/\">%4</a> for more information.</p>")
+                   .arg(Application.version).arg("qt.io/licensing").arg("2023").arg("qt.io")
+          color: Colors.textFile
+          wrapMode: Text.WordWrap
+          readOnly: true
+          antialiasing: true
+          background: null
+
+          onLinkActivated: function(link) {
+              Qt.openUrlExternally(link)
+          }
+      }
+    }
+
+    ResizeButton {
+        resizeWindow: root
     }
-    ResizeButton {}
 }
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Editor.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Editor.qml
new file mode 100644 (file)
index 0000000..80f7c04
--- /dev/null
@@ -0,0 +1,160 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import FileSystemModule
+
+pragma ComponentBehavior: Bound
+
+// This is the text editor that displays the currently open file, including
+// their corresponding line numbers.
+Rectangle {
+    id: root
+
+    required property string currentFilePath
+    required property bool showLineNumbers
+    property alias text: textArea
+    property int currentLineNumber: -1
+    property int rowHeight: Math.ceil(fontMetrics.lineSpacing)
+
+    color: Colors.background
+
+    onWidthChanged: textArea.update()
+    onHeightChanged: textArea.update()
+
+    RowLayout {
+        anchors.fill: parent
+        // We use a flickable to synchronize the position of the editor and
+        // the line numbers. This is necessary because the line numbers can
+        // extend the available height.
+        Flickable {
+            id: lineNumbers
+
+            // Calculate the width based on the logarithmic scale.
+            Layout.preferredWidth: fontMetrics.averageCharacterWidth
+                * (Math.floor(Math.log10(textArea.lineCount)) + 1) + 10
+            Layout.fillHeight: true
+
+            interactive: false
+            contentY: editorFlickable.contentY
+            visible: textArea.text !== "" && root.showLineNumbers
+
+            Column {
+                anchors.fill: parent
+                Repeater {
+                    id: repeatedLineNumbers
+
+                    model: LineNumberModel {
+                        lineCount: textArea.text !== "" ? textArea.lineCount : 0
+                    }
+
+                    delegate: Item {
+                        required property int index
+
+                        width: parent.width
+                        height: root.rowHeight
+                        Label {
+                            id: numbers
+
+                            text: parent.index + 1
+
+                            width: parent.width
+                            height: parent.height
+                            horizontalAlignment: Text.AlignLeft
+                            verticalAlignment: Text.AlignVCenter
+
+                            color: (root.currentLineNumber === parent.index)
+                                    ? Colors.iconIndicator : Qt.darker(Colors.text, 2)
+                            font: textArea.font
+                        }
+                        Rectangle {
+                            id: indicator
+
+                            anchors.left: numbers.right
+                            width: 1
+                            height: parent.height
+                            color: Qt.darker(Colors.text, 3)
+                        }
+                    }
+                }
+            }
+        }
+
+        Flickable {
+            id: editorFlickable
+
+            property alias textArea: textArea
+
+            // We use an inline component to customize the horizontal and vertical
+            // scroll-bars. This is convenient when the component is only used in one file.
+            component MyScrollBar: ScrollBar {
+                id: scrollBar
+                background: Rectangle {
+                    implicitWidth: scrollBar.interactive ? 8 : 4
+                    implicitHeight: scrollBar.interactive ? 8 : 4
+
+                    opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0
+                    color: Colors.background
+                    Behavior on opacity {
+                        OpacityAnimator {
+                            duration: 500
+                        }
+                    }
+                }
+                contentItem: Rectangle {
+                    implicitWidth: scrollBar.interactive ? 8 : 4
+                    implicitHeight: scrollBar.interactive ? 8 : 4
+                    opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0
+                    color: Colors.color1
+                    Behavior on opacity {
+                        OpacityAnimator {
+                            duration: 1000
+                        }
+                    }
+                }
+            }
+
+            Layout.fillHeight: true
+            Layout.fillWidth: true
+            ScrollBar.horizontal: MyScrollBar {}
+            ScrollBar.vertical: MyScrollBar {}
+
+            boundsBehavior: Flickable.StopAtBounds
+
+            TextArea.flickable: TextArea {
+                id: textArea
+                anchors.fill: parent
+
+                focus: false
+                topPadding: 0
+                leftPadding: 10
+
+                text: FileSystemModel.readFile(root.currentFilePath)
+                tabStopDistance: fontMetrics.averageCharacterWidth * 4
+
+                // Grab the current line number from the C++ interface.
+                onCursorPositionChanged: {
+                    root.currentLineNumber = FileSystemModel.currentLineNumber(
+                        textArea.textDocument, textArea.cursorPosition)
+                }
+
+                color: Colors.textFile
+                selectedTextColor: Colors.textFile
+                selectionColor: Colors.selection
+
+                textFormat: TextEdit.PlainText
+                renderType: Text.QtRendering
+                selectByMouse: true
+                antialiasing: true
+                background: null
+            }
+
+            FontMetrics {
+                id: fontMetrics
+                font: textArea.font
+            }
+        }
+    }
+}
index ade2e48c1f5d3fea7fbb3ac011c7b94ac2fea7c8..db955168c59dcde0fee507b134223f79bf209f2b 100644 (file)
@@ -2,26 +2,31 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
 
 import QtQuick
-import QtQuick.Layouts
+import QtQuick.Effects
 import QtQuick.Controls.Basic
 import FileSystemModule
 
+pragma ComponentBehavior: Bound
+
 // This is the file system view which gets populated by the C++ model.
 Rectangle {
     id: root
 
     signal fileClicked(string filePath)
+    property alias rootIndex: fileSystemTreeView.rootIndex
 
     TreeView {
         id: fileSystemTreeView
+
+        property int lastIndex: -1
+
         anchors.fill: parent
         model: FileSystemModel
+        rootIndex: FileSystemModel.rootIndex
         boundsBehavior: Flickable.StopAtBounds
         boundsMovement: Flickable.StopAtBounds
         clip: true
 
-        property int lastIndex: -1
-
         Component.onCompleted: fileSystemTreeView.toggleExpanded(0)
 
         // The delegate represents a single entry in the filesystem.
@@ -31,50 +36,101 @@ Rectangle {
             implicitWidth: fileSystemTreeView.width > 0 ? fileSystemTreeView.width : 250
             implicitHeight: 25
 
+            // Since we have the 'ComponentBehavior Bound' pragma, we need to
+            // require these properties from our model. This is a convenient way
+            // to bind the properties provided by the model's role names.
             required property int index
             required property url filePath
+            required property string fileName
 
-            indicator: null
-
-            contentItem: Item {
-                anchors.fill: parent
+            indicator: Image {
+                id: directoryIcon
 
-                Icon {
-                    id: directoryIcon
-                    x: leftMargin + (depth * indentation)
-                    anchors.verticalCenter: parent.verticalCenter
-                    path: treeDelegate.hasChildren
-                        ? (treeDelegate.expanded ? "../icons/folder_open.svg" : "../icons/folder_closed.svg")
+                x: treeDelegate.leftMargin + (treeDelegate.depth * treeDelegate.indentation)
+                anchors.verticalCenter: parent.verticalCenter
+                source: treeDelegate.hasChildren ? (treeDelegate.expanded
+                            ? "../icons/folder_open.svg" : "../icons/folder_closed.svg")
                         : "../icons/generic_file.svg"
-                    iconColor: (treeDelegate.expanded && treeDelegate.hasChildren) ? Colors.color2 : Colors.folder
-                }
-                Text {
-                    anchors.left: directoryIcon.right
-                    anchors.verticalCenter: parent.verticalCenter
-                    width: parent.width
-                    text: model.fileName
-                    color: Colors.text
-                }
+                sourceSize.width: 20
+                sourceSize.height: 20
+                fillMode: Image.PreserveAspectFit
+
+                smooth: true
+                antialiasing: true
+                asynchronous: true
+            }
+
+            contentItem: Text {
+                text: treeDelegate.fileName
+                color: Colors.text
             }
 
             background: Rectangle {
-                color: treeDelegate.index === fileSystemTreeView.lastIndex
+                color: (treeDelegate.index === fileSystemTreeView.lastIndex)
                     ? Colors.selection
                     : (hoverHandler.hovered ? Colors.active : "transparent")
             }
 
-            TapHandler {
-                onSingleTapped: {
-                    fileSystemTreeView.toggleExpanded(row)
-                    fileSystemTreeView.lastIndex = index
-                    // If this model item doesn't have children, it means it's representing a file.
-                    if (!treeDelegate.hasChildren)
-                        root.fileClicked(filePath)
+            // We color the directory icons with this MultiEffect, where we overlay
+            // the colorization color ontop of the SVG icons.
+            MultiEffect {
+                id: iconOverlay
+
+                anchors.fill: directoryIcon
+                source: directoryIcon
+                colorization: 1.0
+                brightness: 1.0
+                colorizationColor: {
+                    const isFile = treeDelegate.index === fileSystemTreeView.lastIndex
+                                    && !treeDelegate.hasChildren;
+                    if (isFile)
+                        return Qt.lighter(Colors.folder, 3)
+
+                    const isExpandedFolder = treeDelegate.expanded && treeDelegate.hasChildren;
+                    if (isExpandedFolder)
+                        return Colors.color2
+                    else
+                        return Colors.folder
                 }
             }
+
             HoverHandler {
                 id: hoverHandler
             }
+
+            TapHandler {
+                acceptedButtons: Qt.LeftButton | Qt.RightButton
+                onSingleTapped: (eventPoint, button) => {
+                    switch (button) {
+                        case Qt.LeftButton:
+                            fileSystemTreeView.toggleExpanded(treeDelegate.row)
+                            fileSystemTreeView.lastIndex = treeDelegate.index
+                            // If this model item doesn't have children, it means it's
+                            // representing a file.
+                            if (!treeDelegate.hasChildren)
+                                root.fileClicked(treeDelegate.filePath)
+                        break;
+                        case Qt.RightButton:
+                            if (treeDelegate.hasChildren)
+                                contextMenu.popup();
+                        break;
+                    }
+                }
+            }
+
+            MyMenu {
+                id: contextMenu
+                Action {
+                    text: qsTr("Set as root index")
+                    onTriggered: {
+                        fileSystemTreeView.rootIndex = fileSystemTreeView.index(treeDelegate.row, 0)
+                    }
+                }
+                Action {
+                    text: qsTr("Reset root index")
+                    onTriggered: fileSystemTreeView.rootIndex = undefined
+                }
+            }
         }
 
         // Provide our own custom ScrollIndicator for the TreeView.
@@ -85,6 +141,7 @@ Rectangle {
             contentItem: Rectangle {
                 implicitWidth: 6
                 implicitHeight: 6
+
                 color: Colors.color1
                 opacity: fileSystemTreeView.movingVertically ? 0.5 : 0.0
 
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Icon.qml b/sources/pyside6/doc/tutorials/extendedexplorer/FileSystemModule/qml/Icon.qml
deleted file mode 100644 (file)
index 25162d9..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-import QtQuick
-import QtQuick.Effects
-
-// Custom Component for displaying Icons
-Item {
-    id: root
-
-    required property url path
-    property real padding: 5
-    property real size: 30
-    property alias iconColor: overlay.colorizationColor
-    property alias hovered: mouse.hovered
-
-    width: size
-    height: size
-
-    Image {
-        id: icon
-        anchors.fill: root
-        anchors.margins: padding
-        source: path
-        sourceSize: Qt.size(size, size)
-        fillMode: Image.PreserveAspectFit
-        smooth: true
-        antialiasing: true
-        asynchronous: true
-    }
-
-    MultiEffect {
-        id: overlay
-        anchors.fill: icon
-        source: icon
-        colorization: 1.0
-        brightness: 1.0
-    }
-
-    HoverHandler {
-        id: mouse
-        acceptedDevices: PointerDevice.Mouse
-    }
-}
index 99795b5e53f77f09213842c14e4e1c21feff8fd6..1f1d30c56697425b07b1ffbfda8e23e94bcd4ff5 100644 (file)
@@ -8,35 +8,38 @@ import FileSystemModule
 Menu {
     id: root
 
-    background: Rectangle {
-        implicitWidth: 200
-        implicitHeight: 40
-        color: Colors.surface2
-    }
-
     delegate: MenuItem {
         id: menuItem
-        implicitWidth: 200
-        implicitHeight: 40
         contentItem: Item {
             Text {
                 anchors.verticalCenter: parent.verticalCenter
                 anchors.left: parent.left
                 anchors.leftMargin: 5
+
                 text: menuItem.text
                 color: enabled ? Colors.text : Colors.disabledText
             }
             Rectangle {
+                id: indicator
+
                 anchors.verticalCenter: parent.verticalCenter
                 anchors.right: parent.right
                 width: 6
                 height: parent.height
+
                 visible: menuItem.highlighted
                 color: Colors.color2
             }
         }
         background: Rectangle {
+            implicitWidth: 210
+            implicitHeight: 35
             color: menuItem.highlighted ? Colors.active : "transparent"
         }
     }
+    background: Rectangle {
+        implicitWidth: 210
+        implicitHeight: 35
+        color: Colors.surface2
+    }
 }
index a2a3fea8861f85062a13fb82cc47feef260927a2..4874a2c03f270daa3a7bcda967736f6c2bfd6685 100644 (file)
@@ -6,130 +6,172 @@ import QtQuick.Layouts
 import QtQuick.Controls.Basic
 import FileSystemModule
 
-// The MenuBar also serves as a controller for our Window as we don't use any decorations.
+// The MenuBar also serves as a controller for our window as we don't use any decorations.
 MenuBar {
     id: root
 
-    required property ApplicationWindow rootWindow
+    required property ApplicationWindow dragWindow
     property alias infoText: windowInfo.text
 
-    implicitHeight: 25
-
-    // The top level menus on the left side
+    // Customization of the top level menus inside the MenuBar
     delegate: MenuBarItem {
         id: menuBarItem
-        implicitHeight: 25
 
         contentItem: Text {
             horizontalAlignment: Text.AlignLeft
             verticalAlignment: Text.AlignVCenter
-            color: menuBarItem.highlighted ? Colors.textFile : Colors.text
-            opacity: enabled ? 1.0 : 0.3
+
             text: menuBarItem.text
-            elide: Text.ElideRight
             font: menuBarItem.font
+            elide: Text.ElideRight
+            color: menuBarItem.highlighted ? Colors.textFile : Colors.text
+            opacity: enabled ? 1.0 : 0.3
         }
 
         background: Rectangle {
+            id: background
+
             color: menuBarItem.highlighted ? Colors.selection : "transparent"
             Rectangle {
                 id: indicator
+
                 width: 0; height: 3
                 anchors.horizontalCenter: parent.horizontalCenter
                 anchors.bottom: parent.bottom
-                color: Colors.color1
 
+                color: Colors.color1
                 states: State {
-                    name: "active"; when: menuBarItem.highlighted
-                    PropertyChanges { target: indicator; width: parent.width }
+                    name: "active"
+                    when: menuBarItem.highlighted
+                    PropertyChanges {
+                        indicator.width: background.width - 2
+                    }
                 }
-
                 transitions: Transition {
                     NumberAnimation {
                         properties: "width"
-                        duration: 300
+                        duration: 175
                     }
                 }
-
             }
         }
     }
+    // We use the contentItem property as a place to attach our window decorations. Beneath
+    // the usual menu entries within a MenuBar, it includes a centered information text, along
+    // with the minimize, maximize, and close buttons.
+    contentItem: RowLayout {
+        id: windowBar
 
-    // The background property contains an information text in the middle as well as the
-    // Minimize, Maximize and Close Buttons.
-    background: Rectangle {
-        color: Colors.surface2
-        // Make the empty space drag the specified root window.
-        WindowDragHandler { dragWindow: rootWindow }
+        Layout.fillWidth: true
+        Layout.fillHeight: true
+
+        spacing: root.spacing
+        Repeater {
+            id: menuBarItems
 
-        Text {
-            id: windowInfo
-            anchors.horizontalCenter: parent.horizontalCenter
-            anchors.verticalCenter: parent.verticalCenter
-            color: Colors.text
+            Layout.alignment: Qt.AlignLeft
+            model: root.contentModel
         }
 
-        component InteractionButton: Rectangle {
-            signal action;
-            property alias hovered: hoverHandler.hovered
+        Item {
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+            Text {
+                id: windowInfo
+
+                width: parent.width; height: parent.height
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+                leftPadding: windowActions.width
+                color: Colors.text
+                clip: true
+            }
+        }
 
-            width: root.height
-            anchors.top: parent.top
-            anchors.bottom: parent.bottom
-            color: hovered ? Colors.background : "transparent"
+        RowLayout {
+            id: windowActions
 
-            HoverHandler { id: hoverHandler }
-            TapHandler { onTapped: action() }
-        }
+            Layout.alignment: Qt.AlignRight
+            Layout.fillHeight: true
 
-        InteractionButton {
-            id: minimize
+            spacing: 0
 
-            anchors.right: maximize.left
-            onAction: rootWindow.showMinimized()
-            Rectangle {
-                width: parent.height - 10; height: 2
-                anchors.centerIn: parent
-                color: parent.hovered ? Colors.iconIndicator : Colors.icon
+            component InteractionButton: Rectangle {
+                id: interactionButton
+
+                signal action()
+                property alias hovered: hoverHandler.hovered
+
+                Layout.fillHeight: true
+                Layout.preferredWidth: height
+
+                color: hovered ? Colors.background : "transparent"
+                HoverHandler {
+                    id: hoverHandler
+                }
+                TapHandler {
+                    id: tapHandler
+                    onTapped: interactionButton.action()
+                }
             }
-        }
 
-        InteractionButton {
-            id: maximize
+            InteractionButton {
+                id: minimize
 
-            anchors.right: close.left
-            onAction: rootWindow.showMaximized()
-            Rectangle {
-                anchors.fill: parent
-                anchors.margins: 5
-                border.width: 2
-                color: "transparent"
-                border.color: parent.hovered ? Colors.iconIndicator : Colors.icon
+                onAction: root.dragWindow.showMinimized()
+                Rectangle {
+                    anchors.centerIn: parent
+                    color: parent.hovered ? Colors.iconIndicator : Colors.icon
+                    height: 2
+                    width: parent.height - 14
+                }
             }
-        }
 
-        InteractionButton {
-            id: close
+            InteractionButton {
+                id: maximize
 
-            color: hovered ? "#ec4143" : "transparent"
-            anchors.right: parent.right
-            onAction: rootWindow.close()
-            Rectangle {
-                width: parent.height - 8; height: 2
-                anchors.centerIn: parent
-                color: parent.hovered ? Colors.iconIndicator : Colors.icon
-                rotation: 45
-                transformOrigin: Item.Center
-                antialiasing: true
+                onAction: root.dragWindow.showMaximized()
+                Rectangle {
+                    anchors.fill: parent
+                    anchors.margins: 7
+                    border.color: parent.hovered ? Colors.iconIndicator : Colors.icon
+                    border.width: 2
+                    color: "transparent"
+                }
+            }
+
+            InteractionButton {
+                id: close
+
+                color: hovered ? "#ec4143" : "transparent"
+                onAction: root.dragWindow.close()
                 Rectangle {
-                    width: parent.height
-                    height: parent.width
                     anchors.centerIn: parent
-                    color: parent.color
+                    width: parent.height - 8; height: 2
+
+                    rotation: 45
                     antialiasing: true
+                    transformOrigin: Item.Center
+                    color: parent.hovered ? Colors.iconIndicator : Colors.icon
+
+                    Rectangle {
+                        anchors.centerIn: parent
+                        width: parent.height
+                        height: parent.width
+
+                        antialiasing: true
+                        color: parent.color
+                    }
                 }
             }
         }
     }
 
+    background: Rectangle {
+        color: Colors.surface2
+        // Make the empty space drag the specified root window.
+        WindowDragHandler {
+            dragWindow: root.dragWindow
+        }
+    }
 }
index eb2e5bc0276617c7f4c0623156edc6cac2b52ef6..0df65bf82f58f293499843980059d206d28b44d4 100644 (file)
@@ -5,6 +5,8 @@ import QtQuick.Controls
 import FileSystemModule
 
 Button {
+    required property ApplicationWindow resizeWindow
+
     icon.width: 20; icon.height: 20
     anchors.right: parent.right
     anchors.bottom: parent.bottom
@@ -12,12 +14,10 @@ Button {
     bottomPadding: 3
 
     icon.source: "../icons/resize.svg"
-    icon.color: down || checked ? Colors.iconIndicator : Colors.icon
+    icon.color: hovered ? Colors.iconIndicator : Colors.icon
 
+    background: null
     checkable: false
     display: AbstractButton.IconOnly
-    background: null
-    onPressed: {
-        root.startSystemResize(Qt.BottomEdge | Qt.RightEdge)
-    }
+    onPressed: resizeWindow.startSystemResize(Qt.BottomEdge | Qt.RightEdge)
 }
index 29062a9bb78602426793820e1e02f5741b576e80..04880a55d48ba87242ba90e8dd7cdd90388093ab 100644 (file)
@@ -8,78 +8,94 @@ import FileSystemModule
 
 Rectangle {
     id: root
+
+    property alias currentTabIndex: topBar.currentIndex
+    required property ApplicationWindow dragWindow
+    readonly property int tabBarSpacing: 10
+
     color: Colors.surface2
 
-    required property ApplicationWindow rootWindow
-    property alias currentTabIndex: tabBar.currentIndex
+    component SidebarEntry: Button {
+        id: sidebarButton
 
-    ColumnLayout {
-        anchors.fill: root
-        anchors.topMargin: 10
-        anchors.bottomMargin: 10
-        spacing: 10
+        Layout.alignment: Qt.AlignHCenter
+        Layout.fillWidth: true
 
-        // TabBar is designed to be horizontal, whereas we need a vertical bar.
-        // We can easily achieve that by using a Container.
-        Container {
-            id: tabBar
+        icon.color: down || checked ? Colors.iconIndicator : Colors.icon
+        icon.width: 27
+        icon.height: 27
 
-            Layout.fillWidth: true
+        topPadding: 0
+        rightPadding: 0
+        bottomPadding: 0
+        leftPadding: 0
+        background: null
 
-            // ButtonGroup ensures that only one button can be checked at a time.
-            ButtonGroup {
-                buttons: tabBar.contentItem.children
-                // We have to manage the currentIndex ourselves, which we do by setting it to the
-                // index of the currently checked button.
-                // We use setCurrentIndex instead of setting the currentIndex property to avoid breaking bindings.
-                // See "Managing the Current Index" in Container's documentation for more information.
-                onCheckedButtonChanged: tabBar.setCurrentIndex(Math.max(0, buttons.indexOf(checkedButton)))
-            }
+        Rectangle {
+            id: indicator
 
-            contentItem: ColumnLayout {
-                spacing: tabBar.spacing
+            anchors.verticalCenter: parent.verticalCenter
+            x: 2
+            width: 4
+            height: sidebarButton.icon.height * 1.2
 
-                Repeater {
-                    model: tabBar.contentModel
-                }
-            }
+            visible: sidebarButton.checked
+            color: Colors.color1
+        }
+    }
+
+    // TabBar is designed to be horizontal, whereas we need a vertical bar.
+    // We can easily achieve that by using a Container.
+    component TabBar: Container {
+        id: tabBarComponent
+
+        Layout.fillWidth: true
+        // ButtonGroup ensures that only one button can be checked at a time.
+        ButtonGroup {
+            buttons: tabBarComponent.contentChildren
+
+            // We have to manage the currentIndex ourselves, which we do by setting it to the index
+            // of the currently checked button. We use setCurrentIndex instead of setting the
+            // currentIndex property to avoid breaking bindings. See "Managing the Current Index"
+            // in Container's documentation for more information.
+            onCheckedButtonChanged: tabBarComponent.setCurrentIndex(
+                Math.max(0, buttons.indexOf(checkedButton)))
+        }
 
-            component SidebarEntry: Button {
-                id: sidebarButton
-                icon.color: down || checked ? Colors.iconIndicator : Colors.icon
-                icon.width: 35
-                icon.height: 35
-                leftPadding: 8 + indicator.width
-
-                background: null
-
-                Rectangle {
-                    id: indicator
-                    x: 4
-                    anchors.verticalCenter: parent.verticalCenter
-                    width: 4
-                    height: sidebarButton.icon.width
-                    color: Colors.color1
-                    visible: sidebarButton.checked
-                }
+        contentItem: ColumnLayout {
+            spacing: tabBarComponent.spacing
+            Repeater {
+                model: tabBarComponent.contentModel
             }
+        }
+    }
 
+    ColumnLayout {
+        anchors.fill: root
+        anchors.topMargin: root.tabBarSpacing
+        anchors.bottomMargin: root.tabBarSpacing
+
+        spacing: root.tabBarSpacing
+        TabBar {
+            id: topBar
+
+            spacing: root.tabBarSpacing
             // Shows help text when clicked.
             SidebarEntry {
+                id: infoTab
                 icon.source: "../icons/light_bulb.svg"
                 checkable: true
                 checked: true
-
-                Layout.alignment: Qt.AlignHCenter
             }
 
             // Shows the file system when clicked.
             SidebarEntry {
+                id: filesystemTab
+
                 icon.source: "../icons/read.svg"
                 checkable: true
-
-                Layout.alignment: Qt.AlignHCenter
             }
+
             // Shows the scheme switcher
             SidebarEntry {
                 icon.source: "../icons/leaf.svg"
@@ -95,25 +111,31 @@ Rectangle {
             Layout.fillWidth: true
 
             // Make the empty space drag our main window.
-            WindowDragHandler { dragWindow: rootWindow }
+            WindowDragHandler {
+                dragWindow: root.dragWindow
+            }
         }
 
-        // Opens the Qt website in the system's web browser.
-        SidebarEntry {
-            id: qtWebsiteButton
-            icon.source: "../icons/globe.svg"
-            checkable: false
+        TabBar {
+            id: bottomBar
 
-            onClicked: Qt.openUrlExternally("https://www.qt.io/")
-        }
+            spacing: root.tabBarSpacing
+            // Opens the Qt website in the system's web browser.
+            SidebarEntry {
+                id: qtWebsiteButton
+                icon.source: "../icons/globe.svg"
+                checkable: false
+                onClicked: Qt.openUrlExternally("https://www.qt.io/")
+            }
 
-        // Opens the About Qt Window.
-        SidebarEntry {
-            id: aboutQtButton
-            icon.source: "../icons/info_sign.svg"
-            checkable: false
+            // Opens the About Qt Window.
+            SidebarEntry {
+                id: aboutQtButton
 
-            onClicked: aboutQtWindow.visible = !aboutQtWindow.visible
+                icon.source: "../icons/info_sign.svg"
+                checkable: false
+                onClicked: aboutQtWindow.visible = !aboutQtWindow.visible
+            }
         }
     }
 
index 6c9e3ed9b025e9efee575f51d1de8a6a80f76d6b..e9c99b07bad58718c7606a1d40a77dd2a9df4edc 100644 (file)
@@ -1,7 +1,7 @@
 module FileSystemModule
 Main 1.0 Main.qml
-Icon 1.0 qml/Icon.qml
 About 1.0 qml/About.qml
+Editor 1.0 qml/Editor.qml
 MyMenu 1.0 qml/MyMenu.qml
 Sidebar 1.0 qml/Sidebar.qml
 MyMenuBar 1.0 qml/MyMenuBar.qml
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/editormodels.py b/sources/pyside6/doc/tutorials/extendedexplorer/editormodels.py
new file mode 100644 (file)
index 0000000..6881477
--- /dev/null
@@ -0,0 +1,116 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtWidgets import QFileSystemModel
+from PySide6.QtQuick import QQuickTextDocument
+from PySide6.QtQml import QmlElement, QmlSingleton
+from PySide6.QtCore import (Qt, QDir, QAbstractListModel, Slot, QFile, QTextStream,
+                            QMimeDatabase, QFileInfo, QStandardPaths, QModelIndex,
+                            Signal, Property)
+
+QML_IMPORT_NAME = "FileSystemModule"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+@QmlElement
+@QmlSingleton
+class FileSystemModel(QFileSystemModel):
+
+    rootIndexChanged = Signal()
+
+    def getDefaultRootDir():
+        return QStandardPaths.writableLocation(QStandardPaths.StandardLocation.HomeLocation)
+
+    def __init__(self, parent=None):
+        super().__init__(parent=parent)
+        self.mRootIndex = QModelIndex()
+        self.mDb = QMimeDatabase()
+        self.setFilter(QDir.Filter.AllEntries | QDir.Filter.Hidden | QDir.Filter.NoDotAndDotDot)
+        self.setInitialDirectory()
+
+    # check for the correct mime type and then read the file.
+    # returns the text file's content or an error message on failure
+    @Slot(str, result=str)
+    def readFile(self, path):
+        if path == "":
+            return ""
+
+        file = QFile(path)
+
+        mime = self.mDb.mimeTypeForFile(QFileInfo(file))
+        if ('text' in mime.comment().lower()
+                or any('text' in s.lower() for s in mime.parentMimeTypes())):
+            if file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text):
+                stream = QTextStream(file).readAll()
+                file.close()
+                return stream
+            else:
+                return self.tr("Error opening the file!")
+        return self.tr("File type not supported!")
+
+    @Slot(QQuickTextDocument, int, result=int)
+    def currentLineNumber(self, textDocument, cursorPosition):
+        td = textDocument.textDocument()
+        tb = td.findBlock(cursorPosition)
+        return tb.blockNumber()
+
+    def setInitialDirectory(self, path=getDefaultRootDir()):
+        dir = QDir(path)
+        if dir.makeAbsolute():
+            self.setRootPath(dir.path())
+        else:
+            self.setRootPath(self.getDefaultRootDir())
+        self.setRootIndex(self.index(dir.path()))
+
+    # we only need one column in this example
+    def columnCount(self, parent):
+        return 1
+
+    @Property(QModelIndex, notify=rootIndexChanged)
+    def rootIndex(self):
+        return self.mRootIndex
+
+    def setRootIndex(self, index):
+        if (index == self.mRootIndex):
+            return
+        self.mRootIndex = index
+        self.rootIndexChanged.emit()
+
+
+@QmlElement
+class LineNumberModel(QAbstractListModel):
+
+    lineCountChanged = Signal()
+
+    def __init__(self, parent=None):
+        self.mLineCount = 0
+        super().__init__(parent=parent)
+
+    @Property(int, notify=lineCountChanged)
+    def lineCount(self):
+        return self.mLineCount
+
+    @lineCount.setter
+    def lineCount(self, n):
+        if n < 0:
+            print("lineCount must be greater then zero")
+            return
+        if self.mLineCount == n:
+            return
+
+        if self.mLineCount < n:
+            self.beginInsertRows(QModelIndex(), self.mLineCount, n - 1)
+            self.mLineCount = n
+            self.endInsertRows()
+        else:
+            self.beginRemoveRows(QModelIndex(), n, self.mLineCount - 1)
+            self.mLineCount = n
+            self.endRemoveRows()
+
+    def rowCount(self, parent):
+        return self.mLineCount
+
+    def data(self, index, role):
+        if not self.checkIndex(index) or role != Qt.ItemDataRole.DisplayRole:
+            return
+        return index.row()
index 7e265a7ef822937f919a461430d237256759f32d..0ac7bec18a16a1b623ff670f36ba0f62fe9be552 100644 (file)
@@ -151,7 +151,7 @@ by adding a new entry to the `Sidebar.qml` file.
 language: QML
 caption: true
 linenos: true
-lines: 83-90
+lines: 99-105
 ---
 ```
 
@@ -164,7 +164,7 @@ modified. The necessary changes will be made to the Main.qml file:
 language: QML
 caption: true
 linenos: true
-lines: 169-198
+lines: 170-187
 ---
 ```
 
@@ -178,7 +178,7 @@ will also be made to the Main.qml file.
 language: QML
 caption: true
 linenos: true
-lines: 144-145
+lines: 147-150
 ---
 ```
 
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.py b/sources/pyside6/doc/tutorials/extendedexplorer/extendedexplorer.py
deleted file mode 100644 (file)
index 6ad6e92..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-"""
-This example shows how to customize Qt Quick Controls by implementing a simple filesystem explorer.
-"""
-
-# Compile both resource files app.qrc and icons.qrc and include them here if you wish
-# to load them from the resource system. Currently, all resources are loaded locally
-# import FileSystemModule.rc_icons
-# import FileSystemModule.rc_app
-from scheme_manager import SchemeManager
-
-from PySide6.QtWidgets import QFileSystemModel
-from PySide6.QtGui import QGuiApplication
-from PySide6.QtQml import (QQmlApplicationEngine, QmlElement, QmlSingleton)
-from PySide6.QtCore import (Slot, QFile, QTextStream, QMimeDatabase, QFileInfo, QStandardPaths)
-
-import sys
-
-
-QML_IMPORT_NAME = "FileSystemModule"
-QML_IMPORT_MAJOR_VERSION = 1
-
-
-@QmlElement
-@QmlSingleton
-class FileSystemModel(QFileSystemModel):
-    def __init__(self, parent=None):
-        super().__init__(parent=parent)
-        self.setRootPath(QStandardPaths.writableLocation(QStandardPaths.HomeLocation))
-        self.db = QMimeDatabase()
-
-    # we only need one column in this example
-    def columnCount(self, parent):
-        return 1
-
-    # check for the correct mime type and then read the file.
-    # returns the text file's content or an error message on failure
-    @Slot(str, result=str)
-    def readFile(self, path):
-        if path == "":
-            return ""
-
-        file = QFile(path)
-
-        mime = self.db.mimeTypeForFile(QFileInfo(file))
-        if 'text' in mime.comment().lower() or any('text' in s.lower() for s in mime.parentMimeTypes()):
-            if file.open(QFile.ReadOnly | QFile.Text):
-                stream = QTextStream(file).readAll()
-                return stream
-            else:
-                return self.tr("Error opening the file!")
-        return self.tr("File type not supported!")
-
-
-if __name__ == '__main__':
-    app = QGuiApplication(sys.argv)
-    app.setOrganizationName("QtProject")
-    app.setApplicationName("File System Explorer")
-    engine = QQmlApplicationEngine()
-    # Include the path of this file to search for the 'qmldir' module
-    engine.addImportPath(sys.path[0])
-
-    engine.loadFromModule("FileSystemModule", "Main")
-
-    if not engine.rootObjects():
-        sys.exit(-1)
-
-    sys.exit(app.exec())
index f6f2e4e89d01cc7270fe7c935346c03d644540b8..77a3969ae0e859db378b89bcaa0d570dd2c71b4e 100644 (file)
@@ -1,21 +1,23 @@
 {
  "files": [
-    "extendedexplorer.py",
-    "color_scheme.py",
+    "main.py",
+    "editormodels.py",
+    "scheme_manager.py",
+    "schemes.json",
     "FileSystemModule/qmldir",
     "FileSystemModule/app.qrc",
     "FileSystemModule/icons.qrc",
-    "FileSystemModule/qmldir",
     "FileSystemModule/Main.qml",
     "FileSystemModule/qml/About.qml",
     "FileSystemModule/qml/ColorScheme.qml",
+    "FileSystemModule/qml/Editor.qml",
     "FileSystemModule/qml/FileSystemView.qml",
-    "FileSystemModule/qml/Icon.qml",
     "FileSystemModule/qml/MyMenu.qml",
     "FileSystemModule/qml/MyMenuBar.qml",
     "FileSystemModule/qml/ResizeButton.qml",
     "FileSystemModule/qml/Sidebar.qml",
     "FileSystemModule/qml/WindowDragHandler.qml",
+    "FileSystemModule/icons/app_icon.svg",
     "FileSystemModule/icons/folder_closed.svg",
     "FileSystemModule/icons/folder_open.svg",
     "FileSystemModule/icons/generic_file.svg",
diff --git a/sources/pyside6/doc/tutorials/extendedexplorer/main.py b/sources/pyside6/doc/tutorials/extendedexplorer/main.py
new file mode 100644 (file)
index 0000000..f1e6e7d
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+"""
+This example shows how to customize Qt Quick Controls by implementing a simple filesystem explorer.
+"""
+
+# Compile both resource files app.qrc and icons.qrc and include them here if you wish
+# to load them from the resource system. Currently, all resources are loaded locally
+# import FileSystemModule.rc_icons
+# import FileSystemModule.rc_app
+
+from scheme_manager import SchemeManager
+from editormodels import FileSystemModel
+import PySide6
+from PySide6.QtGui import QGuiApplication, QIcon
+from PySide6.QtQml import QQmlApplicationEngine
+from PySide6.QtCore import QCommandLineParser
+
+import sys
+
+if __name__ == '__main__':
+    app = QGuiApplication(sys.argv)
+    app.setOrganizationName("QtProject")
+    app.setApplicationName("File System Explorer")
+    app.setApplicationVersion(PySide6.__version__)
+    app.setWindowIcon(QIcon("FileSystemModule/icons/app_icon.svg"))
+
+    parser = QCommandLineParser()
+    parser.setApplicationDescription("Qt Filesystemexplorer Example")
+    parser.addHelpOption()
+    parser.addVersionOption()
+    parser.addPositionalArgument("", "Initial directory", "[path]")
+    parser.process(app)
+    args = parser.positionalArguments()
+
+    engine = QQmlApplicationEngine()
+    # Include the path of this file to search for the 'qmldir' module
+    engine.addImportPath(sys.path[0])
+
+    engine.loadFromModule("FileSystemModule", "Main")
+
+    if not engine.rootObjects():
+        sys.exit(-1)
+
+    if (len(args) == 1):
+        fsm = engine.singletonInstance("FileSystemModule", "FileSystemModel")
+        fsm.setInitialDirectory(args[0])
+
+    sys.exit(app.exec())
index 1f4e2cfa785177d8993ff8f498c2c9e6674862b3..79a14f34cd4473f7164111a7f9a06dd11dc0c7ba 100644 (file)
Binary files a/sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.webp and b/sources/pyside6/doc/tutorials/extendedexplorer/resources/extendedexplorer.webp differ
index b77648d6a3b7ebf6259b9c3e43153b516da0c478..c6d72e74202e34b3049de03ff8d8972601d4fa02 100644 (file)
@@ -15,15 +15,15 @@ defined in the QML file.
 Before you begin, install the following prerequisites:
 
 * The `PySide6 <https://pypi.org/project/PySide6/>`_ Python packages.
-* Qt Creator v4.9 beta1 or later from
+* *Qt Creator* from
   `https://download.qt.io
   <https://download.qt.io/snapshots/qtcreator/>`_.
 
 
 The following step-by-step instructions guide you through application
-development process using Qt Creator:
+development process using *Qt Creator*:
 
-#. Open Qt Creator and select **File > New File or Project..** menu item
+#. Open *Qt Creator* and select **File > New File or Project..** menu item
    to open following dialog:
 
    .. image:: newpyproject.png
index e9fd0d56ecee92374fa886e7727783a400bf0bf0..ebfe123dda323b4a95af7a0f2a57911438735e42 100644 (file)
@@ -8,7 +8,6 @@ set(libpyside_libraries Qt::Core Qt::CorePrivate)
 set(CMAKE_AUTOMOC ON)
 
 set(libpyside_HEADERS # installed below
-    pysideqslotobject_p.h
     class_property.h
     dynamicqmetaobject.h
     feature_select.h
@@ -33,6 +32,7 @@ set(libpyside_HEADERS # installed below
     pysideqhash.h
     pysideqmetatype.h
     pysideqobject.h
+    pysideqslotobject_p.h
     pysidesignal.h
     pysidesignal_p.h
     pysideslot_p.h
@@ -44,7 +44,6 @@ set(libpyside_HEADERS # installed below
 )
 
 set(libpyside_SRC
-    pysideqslotobject_p.cpp
     class_property.cpp
     dynamicqmetaobject.cpp
     feature_select.cpp
@@ -53,6 +52,7 @@ set(libpyside_SRC
     pysideclassdecorator.cpp
     pysideclassinfo.cpp
     pysideqenum.cpp
+    pysideqslotobject_p.cpp
     pysidemetafunction.cpp
     pysidesignal.cpp
     pysideslot.cpp
index 99104445c0c74efc3e8989b00e3a19c24104496c..2bed97ef5e2e4c5e13fd46ef039c7807e11d6fb1 100644 (file)
@@ -5,6 +5,7 @@
 #include "pysidestaticstrings.h"
 #include "feature_select.h"
 
+#include <pep384ext.h>
 #include <shiboken.h>
 #include <sbkstaticstrings.h>
 
@@ -23,14 +24,14 @@ extern "C" {
 // `class_property.__get__()`: Always pass the class instead of the instance.
 static PyObject *PyClassProperty_descr_get(PyObject *self, PyObject * /*ob*/, PyObject *cls)
 {
-    return PyProperty_Type.tp_descr_get(self, cls, cls);
+    return PepExt_Type_GetDescrGetSlot(&PyProperty_Type)(self, cls, cls);
 }
 
 // `class_property.__set__()`: Just like the above `__get__()`.
 static int PyClassProperty_descr_set(PyObject *self, PyObject *obj, PyObject *value)
 {
     PyObject *cls = PyType_Check(obj) ? obj : reinterpret_cast<PyObject *>(Py_TYPE(obj));
-    return PyProperty_Type.tp_descr_set(self, cls, value);
+    return PepExt_Type_GetDescrSetSlot(&PyProperty_Type)(self, cls, value);
 }
 
 // PYSIDE-2230: Why is this metaclass necessary?
@@ -80,7 +81,7 @@ static int PyClassProperty_tp_init(PyObject *self, PyObject *args, PyObject *kwa
 {
     auto hold = Py_TYPE(self);
     self->ob_type = &PyProperty_Type;
-    auto ret =  PyProperty_Type.tp_init(self, args, kwargs);
+    auto ret = PepExt_Type_GetInitSlot(&PyProperty_Type)(self, args, kwargs);
     self->ob_type = hold;
     return ret;
 }
@@ -138,9 +139,9 @@ static int SbkObjectType_meta_setattro(PyObject *obj, PyObject *name, PyObject *
                                 && !PyObject_IsInstance(value, class_prop);
     if (call_descr_set) {
         // Call `class_property.__set__()` instead of replacing the `class_property`.
-        return Py_TYPE(descr)->tp_descr_set(descr, obj, value);
+        return PepExt_Type_GetDescrSetSlot(Py_TYPE(descr))(descr, obj, value);
     } // Replace existing attribute.
-    return PyType_Type.tp_setattro(obj, name, value);
+    return PepExt_Type_GetSetAttroSlot(&PyType_Type)(obj, name, value);
 }
 
 } // extern "C"
index b41dbc275f7c94ded20767302c19aea4be51035d..048001f81cbbcb6a57b25599066ba27b2f659bd3 100644 (file)
@@ -634,7 +634,7 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
                 const int index = m_baseObject->indexOfProperty(name);
                 if (index == -1)
                     addProperty(name, value);
-            } else if (Py_TYPE(value)->tp_call != nullptr) {
+            } else if (PepType_GetSlot(Py_TYPE(value), Py_tp_call) != nullptr) {
                 // PYSIDE-198: PyFunction_Check does not work with Nuitka.
                 // Register slots.
                 if (PyObject_HasAttr(value, slotAttrName)) {
index 3f8e3887011e13ee5cd924375971620113d362b9..cfd465267befad82b3032909bdb681ea01a068ba 100644 (file)
@@ -107,7 +107,7 @@ createDerivedDictType()
     PyObject *ChameleonDict = PepRun_GetResult(R"CPP(if True:
 
         class ChameleonDict(dict):
-            __slots__ = ("dict_ring", "select_id")
+            __slots__ = ("dict_ring", "select_id", "orig_dict")
 
         result = ChameleonDict
 
@@ -172,9 +172,9 @@ static bool replaceClassDict(PyTypeObject *type)
     // insert the dict into itself as ring
     setNextDict(new_dict, new_dict);
     // We have now an exact copy of the dict with a new type.
-    // Replace `__dict__` which usually has refcount 1 (but see cyclic_test.py)
-    Py_DECREF(PepType_GetDict(type));
     PepType_SetDict(type, new_dict);
+    // PYSIDE-2404: Retain the original dict for easy late init.
+    PyObject_SetAttr(new_dict, PySideName::orig_dict(), dict);
     return true;
 }
 
@@ -185,6 +185,7 @@ static bool addNewDict(PyTypeObject *type, int select_id)
      * A 'false' return is fatal.
      */
     AutoDecRef dict(PepType_GetDict(type));
+    AutoDecRef orig_dict(PyObject_GetAttr(dict, PySideName::orig_dict()));
     auto *ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
     auto *new_dict = PyObject_CallObject(ob_ndt, nullptr);
     if (new_dict == nullptr)
@@ -195,6 +196,8 @@ static bool addNewDict(PyTypeObject *type, int select_id)
     setNextDict(dict, new_dict);
     setNextDict(new_dict, next_dict);
     PepType_SetDict(type, new_dict);
+    // PYSIDE-2404: Retain the original dict for easy late init.
+    PyObject_SetAttr(new_dict, PySideName::orig_dict(), orig_dict);
     return true;
 }
 
@@ -393,12 +396,18 @@ static FeatureProc featureProcArray[] = {
 static bool patch_property_impl();
 static bool is_initialized = false;
 
+static void featureEnableCallback(bool enable)
+{
+    featurePointer = enable ? featureProcArray : nullptr;
+}
+
 void init()
 {
     // This function can be called multiple times.
     if (!is_initialized) {
         featurePointer = featureProcArray;
         initSelectableFeature(SelectFeatureSet);
+        setSelectableFeatureCallback(featureEnableCallback);
         patch_property_impl();
         is_initialized = true;
     }
index 09385645d2b76537bb5ffd6cda2a2185fa4a6c41..51070b4ad06309a05ed59299f9f53e74a069f1bd 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <autodecref.h>
 #include <gilstate.h>
+#include <pep384ext.h>
 
 #include <QtCore/QMetaMethod>
 #include <QtCore/QSet>
@@ -135,7 +136,7 @@ PyObject *DynamicSlotDataV2::callback()
 
     //create a callback based on method data
     if (m_isMethod)
-        callback = Py_TYPE(m_callback)->tp_descr_get(m_callback, m_pythonSelf, nullptr);
+        callback = PepExt_Type_CallDescrGet(m_callback, m_pythonSelf, nullptr);
     else
         Py_INCREF(callback);
 
@@ -161,7 +162,7 @@ void DynamicSlotDataV2::onCallbackDestroyed(void *data)
     auto self = reinterpret_cast<DynamicSlotDataV2 *>(data);
     self->m_weakRef = nullptr;
     Py_BEGIN_ALLOW_THREADS
-    SignalManager::instance().deleteGobalReceiver(self->m_parent);
+    SignalManager::instance().deleteGlobalReceiver(self->m_parent);
     Py_END_ALLOW_THREADS
 }
 
index 24911c3d04e29b81b8581609cccd6a1a54932bd8..0e3bc562a8da576813465ccad35b05eb5e803a47 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "dynamicqmetaobject.h"
 
+#include <QtCore/QtCompare>
 #include <QtCore/QByteArray>
 #include <QtCore/QHashFunctions>
 #include <QtCore/QObject>
@@ -33,18 +34,14 @@ struct GlobalReceiverKey
     {
         return qHashMulti(seed, k.object, k.method);
     }
+    friend constexpr bool comparesEqual(const GlobalReceiverKey &lhs,
+                                        const GlobalReceiverKey &rhs) noexcept
+    {
+        return lhs.object == rhs.object && lhs.method == rhs.method;
+    }
+    Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(GlobalReceiverKey)
 };
 
-inline bool operator==(const GlobalReceiverKey &k1, const GlobalReceiverKey &k2)
-{
-    return k1.object == k2.object && k1.method == k2.method;
-}
-
-inline bool operator!=(const GlobalReceiverKey &k1, const GlobalReceiverKey &k2)
-{
-    return k1.object != k2.object || k1.method != k2.method;
-}
-
 /// A class used to link C++ Signals to non C++ slots (Python callbacks) by
 /// providing fake slots for QObject::connect().
 /// It keeps a Python callback and the list of QObject senders. It is stored
index 572341e852ece3b200a72d79f422d9cbc89a8e0f..3a06a03e4d7b3fc6eee54e8dbb0c3091d4c06f53 100644 (file)
@@ -32,6 +32,7 @@
 #include <sbkstring.h>
 #include <sbkstaticstrings.h>
 #include <sbkfeature_base.h>
+#include <sbkmodule.h>
 
 #include <QtCore/QByteArray>
 #include <QtCore/QCoreApplication>
@@ -42,6 +43,7 @@
 #include <QtCore/QMutex>
 #include <QtCore/QStack>
 #include <QtCore/QThread>
+#include <QtCore/private/qobject_p.h>
 
 #include <algorithm>
 #include <cstring>
@@ -62,6 +64,20 @@ QT_END_NAMESPACE
 
 Q_LOGGING_CATEGORY(lcPySide, "qt.pyside.libpyside", QtCriticalMsg)
 
+static QObjectData *qt_object_private(const QObject *o)
+{
+    class FriendlyQObject : public QObject {
+    public:
+        using QObject::d_ptr;
+    };
+    return static_cast<const FriendlyQObject *>(o)->d_ptr.data();
+}
+
+static bool hasDynamicMetaObject(const QObject *o)
+{
+    return qt_object_private(o)->metaObject != nullptr;
+}
+
 namespace PySide
 {
 
@@ -446,6 +462,8 @@ void initDynamicMetaObject(PyTypeObject *type, const QMetaObject *base, std::siz
 
 TypeUserData *retrieveTypeUserData(PyTypeObject *pyTypeObj)
 {
+    if (!SbkObjectType_Check(pyTypeObj))
+        return nullptr;
     return reinterpret_cast<TypeUserData *>(Shiboken::ObjectType::getTypeUserData(pyTypeObj));
 }
 
@@ -672,6 +690,32 @@ static void invalidatePtr(any_t *object)
 
 static const char invalidatePropertyName[] = "_PySideInvalidatePtr";
 
+// PYSIDE-2749: Skip over internal QML classes and classes
+// with dynamic meta objects when looking for the best matching
+// type to avoid unnessarily triggering the lazy load mechanism
+// for classes that do not have a binding from things like eventFilter().
+static inline bool isInternalObject(const char *name)
+{
+    return std::strstr(name, "QMLTYPE") != nullptr || std::strstr(name, "QQmlPrivate") != nullptr;
+}
+
+static const QMetaObject *metaObjectCandidate(const QObject *o)
+{
+    auto *metaObject = o->metaObject();
+    // Skip QML helper types and Python objects
+    if (hasDynamicMetaObject(o)) {
+        if (auto *super = metaObject->superClass())
+            metaObject = super;
+    }
+    for (auto *candidate = metaObject; candidate != nullptr; candidate = candidate->superClass()) {
+        if (!isInternalObject(candidate->className())) {
+            metaObject = candidate;
+            break;
+        }
+    }
+    return metaObject;
+}
+
 // PYSIDE-1214, when creating new wrappers for classes inheriting QObject but
 // not exposed to Python, try to find the best-matching (most-derived) Qt
 // class by walking up the meta objects.
@@ -679,7 +723,8 @@ static const char *typeName(const QObject *cppSelf)
 {
     const char *typeName = typeid(*cppSelf).name();
     if (!Shiboken::Conversions::getConverter(typeName)) {
-        for (auto metaObject = cppSelf->metaObject(); metaObject; metaObject = metaObject->superClass()) {
+        auto *metaObject = metaObjectCandidate(cppSelf);
+        for (; metaObject != nullptr; metaObject = metaObject->superClass()) {
             const char *name = metaObject->className();
             if (Shiboken::Conversions::getConverter(name)) {
                 typeName = name;
@@ -849,7 +894,7 @@ bool registerInternalQtConf()
     QString executablePath = QString::fromWCharArray(Py_GetProgramFullPath());
 #else
     // PYSIDE-535: FIXME: Add this function when available.
-    QString executablePath = QLatin1String("missing Py_GetProgramFullPath");
+    QString executablePath = QLatin1StringView("missing Py_GetProgramFullPath");
 #endif // PYPY_VERSION
 
     QString appDirPath = QFileInfo(executablePath).absolutePath();
@@ -1062,9 +1107,15 @@ static void formatPyObjectValue(PyObject *obj, QDebug &debug)
 {
     if (PyType_Check(obj) != 0)
         debug << "type: \"" << pyTypeName(obj) << '"';
-    else if (PyLong_Check(obj) != 0)
-        debug << PyLong_AsLongLong(obj);
-    else if (PyFloat_Check(obj) != 0)
+    else if (PyLong_Check(obj) != 0) {
+        const auto llv = PyLong_AsLongLong(obj);
+        if (PyErr_Occurred() != PyExc_OverflowError) {
+            debug << llv;
+        } else {
+            PyErr_Clear();
+            debug << "0x" << Qt::hex << PyLong_AsUnsignedLongLong(obj) << Qt::dec;
+        }
+    } else if (PyFloat_Check(obj) != 0)
         debug << PyFloat_AsDouble(obj);
     else if (PyUnicode_Check(obj) != 0)
         debug << '"' << pyStringToQString(obj) << '"';
@@ -1118,5 +1169,47 @@ QDebug operator<<(QDebug debug, const debugPyObject &o)
     return debug;
 }
 
-} //namespace PySide
+debugPyBuffer::debugPyBuffer(Py_buffer *b) noexcept : m_buffer(b)
+{
+}
+
+static void formatPy_ssizeArray(QDebug &debug, const char *name, const Py_ssize_t *array, int len)
+{
+    debug << ", " << name << '=';
+    if (array != nullptr) {
+        debug << '[';
+        for (int i = 0; i < len; ++i)
+            debug << array[i] << ' ';
+        debug << ']';
+    } else {
+        debug << '0';
+    }
+}
+
+PYSIDE_API QDebug operator<<(QDebug debug, const debugPyBuffer &b)
+{
+    QDebugStateSaver saver(debug);
+    debug.noquote();
+    debug.nospace();
+    debug << "Py_buffer(";
+    if (b.m_buffer != nullptr) {
+        debug << "obj=" << b.m_buffer->obj
+              << ", buf=" << b.m_buffer->buf << ", len=" << b.m_buffer->len
+              << ", readonly=" <<  b.m_buffer->readonly
+              << ", itemsize=" <<  b.m_buffer->itemsize << ", format=";
+        if (b.m_buffer->format != nullptr)
+            debug << '"' << b.m_buffer->format << '"';
+        else
+            debug << '0';
+        debug << ", ndim=" << b.m_buffer->ndim;
+        formatPy_ssizeArray(debug, "shape", b.m_buffer->shape, b.m_buffer->ndim);
+        formatPy_ssizeArray(debug, "strides", b.m_buffer->strides, b.m_buffer->ndim);
+        formatPy_ssizeArray(debug, "suboffsets", b.m_buffer->suboffsets, b.m_buffer->ndim);
+    } else {
+        debug << '0';
+    }
+    debug << ')';
+    return debug;
+}
 
+} // namespace PySide
index 39b35025bad79dd3c458cf981748f8c911f10920..ec69c5fe71c3c32948227d2e5d71355ebab378c2 100644 (file)
@@ -7,7 +7,7 @@
 #include "pysideqobject.h"
 
 #include <basewrapper.h>
-#include <sbkcppstring.h>
+#include <sbkstring.h>
 
 namespace PySide::ClassDecorator {
 
@@ -63,7 +63,7 @@ int StringDecoratorPrivate::convertToString(PyObject *self, PyObject *args)
         if (PyUnicode_Check(arg)) {
             auto *pData = DecoratorPrivate::get<StringDecoratorPrivate>(self);
             result = 0;
-            Shiboken::String::toCppString(arg, &(pData->m_string));
+            pData->m_string.assign(Shiboken::String::toCString(arg));
         }
     }
     return result;
index 3e4ad75151dd68b06a36837b4a9a635cf9e301c9..6068f6a2ec9bef00b97fa3dbb4754c531ef2b771 100644 (file)
@@ -7,8 +7,9 @@
 #include <pysidemacros.h>
 
 #include <sbkpython.h>
+#include <pep384ext.h>
 
-#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/QByteArray>
 
 #include <array>
 #include <string>
@@ -64,7 +65,7 @@ public:
     /// Init function that retrieves the string parameter using convertToString()
     int tp_init(PyObject *self, PyObject *args, PyObject *kwds) override;
 
-    const std::string &string() const { return m_string; }
+    QByteArray string() const { return m_string; }
 
 protected:
     /// Helper function that retrieves the string parameter
@@ -74,7 +75,7 @@ protected:
     int convertToString(PyObject *self, PyObject *args);
 
 private:
-    std::string m_string;
+    QByteArray m_string;
 };
 
 /// Base class for private objects of class decorator with a type parameter
@@ -119,7 +120,7 @@ struct Methods
 {
     static PyObject *tp_new(PyTypeObject *subtype)
     {
-        auto *result = reinterpret_cast<PySideClassDecorator *>(subtype->tp_alloc(subtype, 0));
+        auto *result = PepExt_TypeCallAlloc<PySideClassDecorator>(subtype, 0);
         result->d = new DecoratorPrivate;
         return reinterpret_cast<PyObject *>(result);
     }
@@ -129,7 +130,7 @@ struct Methods
         auto pySelf = reinterpret_cast<PyObject *>(self);
         auto decorator = reinterpret_cast<PySideClassDecorator *>(self);
         delete decorator->d;
-        Py_TYPE(pySelf)->tp_base->tp_free(self);
+        PepExt_TypeCallFree(Py_TYPE(pySelf)->tp_base, self);
     }
 
     static PyObject *tp_call(PyObject *self, PyObject *args, PyObject *kwds)
index 2cecb0990ccbe2bb6f0fdafa54fa8555a9c33b8b..698cb1c76da3cb9f516f981ac73edb2756e997fa 100644 (file)
@@ -51,25 +51,14 @@ PyObject *ClassInfoPrivate::tp_call(PyObject *self, PyObject *args, PyObject * /
 
     auto *pData = DecoratorPrivate::get<ClassInfoPrivate>(self);
 
-    if (pData->m_alreadyWrapped) {
-        PyErr_SetString(PyExc_TypeError, "This instance of ClassInfo() was already used to wrap an object");
-        return nullptr;
-    }
-
-    bool validClass = false;
+    if (pData->m_alreadyWrapped)
+        return PyErr_Format(PyExc_TypeError, "This instance of ClassInfo() was already used to wrap an object");
 
     PyTypeObject *klassType = reinterpret_cast<PyTypeObject *>(klass);
-    if (auto userData = PySide::retrieveTypeUserData(klassType)) {
-        PySide::MetaObjectBuilder &mo = userData->mo;
-        mo.addInfo(pData->m_data);
-        pData->m_alreadyWrapped = true;
-        validClass = true;
-    }
+    if (!PySide::ClassInfo::setClassInfo(klassType, pData->m_data))
+        return PyErr_Format(PyExc_TypeError, "This decorator can only be used on classes that are subclasses of QObject");
 
-    if (!validClass) {
-        PyErr_SetString(PyExc_TypeError, "This decorator can only be used on classes that are subclasses of QObject");
-        return nullptr;
-    }
+    pData->m_alreadyWrapped = true;
 
     Py_INCREF(klass);
     return klass;
@@ -79,7 +68,7 @@ int ClassInfoPrivate::tp_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
     PyObject *infoDict = nullptr;
     auto size = PyTuple_Size(args);
-    if (size == 1 && !kwds) {
+    if (size == 1 && kwds == nullptr) {
         PyObject *tmp = PyTuple_GET_ITEM(args, 0);
         if (PyDict_Check(tmp))
             infoDict = tmp;
@@ -87,7 +76,7 @@ int ClassInfoPrivate::tp_init(PyObject *self, PyObject *args, PyObject *kwds)
         infoDict = kwds;
     }
 
-    if (!infoDict) {
+    if (infoDict == nullptr) {
         PyErr_Format(PyExc_TypeError, "ClassInfo() takes either keyword argument(s) or "
                                       "a single dictionary argument");
         return -1;
@@ -95,15 +84,17 @@ int ClassInfoPrivate::tp_init(PyObject *self, PyObject *args, PyObject *kwds)
 
     auto *pData = DecoratorPrivate::get<ClassInfoPrivate>(self);
 
-    PyObject *key;
-    PyObject *value;
+    PyObject *key{};
+    PyObject *value{};
     Py_ssize_t pos = 0;
 
     // PyDict_Next causes a segfault if kwds is empty
     if (PyDict_Size(infoDict) > 0) {
         while (PyDict_Next(infoDict, &pos, &key, &value)) {
             if (Shiboken::String::check(key) && Shiboken::String::check(value)) {
-                pData->m_data[Shiboken::String::toCString(key)] = Shiboken::String::toCString(value);
+                ClassInfo info{Shiboken::String::toCString(key),
+                               Shiboken::String::toCString(value)};
+                pData->m_data.append(info);
             } else {
                 PyErr_SetString(PyExc_TypeError, "All keys and values provided to ClassInfo() "
                                                  "must be strings");
@@ -112,7 +103,7 @@ int ClassInfoPrivate::tp_init(PyObject *self, PyObject *args, PyObject *kwds)
         }
     }
 
-    return PyErr_Occurred() ? -1 : 0;
+    return PyErr_Occurred() != nullptr ? -1 : 0;
 }
 
 static const char *ClassInfo_SignatureStrings[] = {
@@ -130,15 +121,38 @@ void init(PyObject *module)
 
 bool checkType(PyObject *pyObj)
 {
-    if (pyObj)
-        return PyType_IsSubtype(Py_TYPE(pyObj), PySideClassInfo_TypeF());
-    return false;
+    return pyObj != nullptr
+        && PyType_IsSubtype(Py_TYPE(pyObj), PySideClassInfo_TypeF()) != 0;
 }
 
-QMap<QByteArray, QByteArray> getMap(PyObject *obj)
+ClassInfoList getClassInfoList(PyObject *decorator)
 {
-    auto *pData = PySide::ClassDecorator::DecoratorPrivate::get<ClassInfoPrivate>(obj);
+    auto *pData = PySide::ClassDecorator::DecoratorPrivate::get<ClassInfoPrivate>(decorator);
     return pData->m_data;
 }
 
-} //namespace PySide::Property
+bool setClassInfo(PyTypeObject *type, const QByteArray &key,
+                  const QByteArray &value)
+{
+    auto *userData = PySide::retrieveTypeUserData(type);
+    const bool result = userData != nullptr;
+    if (result) {
+        PySide::MetaObjectBuilder &mo = userData->mo;
+        mo.addInfo(key, value);
+    }
+    return result;
+}
+
+bool setClassInfo(PyTypeObject *type, const ClassInfoList &list)
+{
+    auto *userData = PySide::retrieveTypeUserData(type);
+    const bool result = userData != nullptr;
+    if (result) {
+        PySide::MetaObjectBuilder &mo = userData->mo;
+        for (const auto &info : list)
+            mo.addInfo(info.key.constData(), info.value.constData());
+    }
+    return result;
+}
+
+} //namespace PySide::ClassInfo
index 82580e0f03494a59f0db57020f9cd976c1f1b9ba..e048658293945ba1475f3f1c0e4fa3b7cab0bf37 100644 (file)
@@ -8,13 +8,25 @@
 
 #include <sbkpython.h>
 
-#include <QtCore/QMap>
 #include <QtCore/QByteArray>
+#include <QtCore/QList>
 
 namespace PySide::ClassInfo {
 
+struct ClassInfo
+{
+    QByteArray key;
+    QByteArray value;
+};
+
+using ClassInfoList = QList<ClassInfo>;
+
 PYSIDE_API bool checkType(PyObject* pyObj);
-PYSIDE_API QMap<QByteArray, QByteArray> getMap(PyObject *obj);
+PYSIDE_API ClassInfoList getClassInfoList(PyObject *decorator);
+
+PYSIDE_API bool setClassInfo(PyTypeObject *type, const QByteArray &key,
+                             const QByteArray &value);
+PYSIDE_API bool setClassInfo(PyTypeObject *type, const ClassInfoList &list);
 
 } // namespace PySide::ClassInfo
 
index eca192537123a3385bfe303796a4e6a91b05d0b4..4ef456f76c82824c4f322bf4d8db1a8904b2767c 100644 (file)
@@ -28,7 +28,7 @@ public:
     int tp_init(PyObject *self, PyObject *args, PyObject *kwds) override;
     const char *name() const override;
 
-    QMap<QByteArray, QByteArray> m_data;
+    ClassInfoList m_data;
     bool m_alreadyWrapped = false;
 };
 
index 953f5c91fe9c1ee6422b3af4feec95c628b368cb..0207ec3a27a56ee1b075bc12d2c026923703094e 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <sbkpython.h>
 
-#include <QtCore/QtGlobal>
+#include <QtCore/qtconfigmacros.h>
 
 QT_BEGIN_NAMESPACE
 class QObject;
index b7c5315709a8de44cc866e0a41d1a133ea95fe15..85e70f7c9d555ebff031e7776628c933b5b1a4df 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <pysidemacros.h>
 
-#include <QtCore/QtGlobal>
+#include <QtCore/qtconfigmacros.h>
 
 QT_FORWARD_DECLARE_CLASS(QMetaType)
 
index 2648ca43c75a52d27c09dbf2f5a461d9750fd737..3720815dbf9694950d11e8957c0e4b5fffa8881d 100644 (file)
@@ -8,6 +8,7 @@
 #include "pysidesignal_p.h"
 
 #include <shiboken.h>
+#include <pep384ext.h>
 #include <signature.h>
 
 using namespace Shiboken;
@@ -179,7 +180,7 @@ void PySidePropertyPrivate::metaCall(PyObject *source, QMetaObject::Call call, v
 
 static PyObject *qpropertyTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
 {
-    auto *me = reinterpret_cast<PySideProperty *>(subtype->tp_alloc(subtype, 0));
+    auto *me = PepExt_TypeCallAlloc<PySideProperty>(subtype, 0);
     me->d = new PySidePropertyPrivate;
     return reinterpret_cast<PyObject *>(me);
 }
@@ -258,7 +259,7 @@ static void qpropertyDeAlloc(PyObject *self)
         Py_DECREF(Py_TYPE(self));
     }
     PyObject_GC_UnTrack(self);
-    Py_TYPE(self)->tp_free(self);
+    PepExt_TypeCallFree(self);
 }
 
 // Create a copy of the property to prevent the @property.setter from modifying
@@ -474,6 +475,7 @@ static const char *Property_SignatureStrings[] = {
     "PySide6.QtCore.Property.read(self,fget:typing.Callable)->PySide6.QtCore.Property",
     "PySide6.QtCore.Property.setter(self,fset:typing.Callable)->PySide6.QtCore.Property",
     "PySide6.QtCore.Property.write(self,fset:typing.Callable)->PySide6.QtCore.Property",
+    "PySide6.QtCore.Property.__call__(self, func:typing.Callable)->PySide6.QtCore.Property",
     nullptr}; // Sentinel
 
 void init(PyObject *module)
index e6e1392a9fd05698f62d15e7b8348f1e1f6f89d1..ae2d295f6aef7998e3368128087fad6ffa3787dc 100644 (file)
@@ -14,7 +14,7 @@ namespace PySide
 /// Hash function used to enable hash on objects not supported by the native Qt
 /// library which have a toString() function.
 template<class T>
-inline Py_ssize_t hash(const T& value)
+[[deprecated]] inline Py_ssize_t hash(const T& value)
 {
     return qHash(value.toString());
 }
index 07453bc124796693bcbe6aa411133ff13d3854fd..f81c5039965253f8461b222aeed4c5a5c8ca89a1 100644 (file)
@@ -8,7 +8,9 @@
 
 #include <pysidemacros.h>
 
-#include <QtCore/QtGlobal>
+#include <QtCore/qtclasshelpermacros.h>
+
+#include <cstddef>
 
 QT_FORWARD_DECLARE_CLASS(QObject)
 QT_FORWARD_DECLARE_STRUCT(QMetaObject)
index f8c23b9128242b821f5c14ccd492ff0d4426720d..11e07cb048db1d4a8c3affdf7dbcc6b1d616a532 100644 (file)
@@ -18,6 +18,7 @@
 #include <QtCore/QObject>
 #include <QtCore/QMetaMethod>
 #include <QtCore/QMetaObject>
+#include <pep384ext.h>
 #include <signature.h>
 
 #include <algorithm>
@@ -298,7 +299,7 @@ static void signalFree(void *vself)
     Py_XDECREF(self->homonymousMethod);
     self->homonymousMethod = nullptr;
 
-    Py_TYPE(pySelf)->tp_base->tp_free(self);
+    PepExt_TypeCallFree(Py_TYPE(pySelf)->tp_base, self);
 }
 
 static PyObject *signalGetItem(PyObject *obSelf, PyObject *key)
@@ -368,7 +369,7 @@ static void signalInstanceFree(void *vself)
         self->d = nullptr;
     }
     self->deleted = true;
-    Py_TYPE(pySelf)->tp_base->tp_free(self);
+    PepExt_TypeCallFree(Py_TYPE(pySelf)->tp_base, self);
 }
 
 // PYSIDE-1523: PyFunction_Check is not accepting compiled functions and
@@ -441,11 +442,35 @@ static FunctionArgumentsResult extractFunctionArgumentsFromSlot(PyObject *slot)
     return ret;
 }
 
-static int argCount(const FunctionArgumentsResult &args)
+struct ArgCount
+{
+    int min;
+    int max;
+};
+
+// Return a pair of minimum / arg count "foo(p1, p2=0)" -> {1, 2}
+ArgCount argCount(const FunctionArgumentsResult &args)
 {
     Q_ASSERT(args.objCode);
-    return (PepCode_GET_FLAGS(args.objCode) & CO_VARARGS) != 0
-        ? -1 : PepCode_GET_ARGCOUNT(args.objCode);
+    ArgCount result{-1, -1};
+    if ((PepCode_GET_FLAGS(args.objCode) & CO_VARARGS) == 0) {
+        result.min = result.max = PepCode_GET_ARGCOUNT(args.objCode);
+        if (args.function != nullptr) {
+            if (auto *defaultArgs = PepFunction_GetDefaults(args.function))
+                result.min -= PyTuple_Size(defaultArgs);
+        }
+    }
+    return result;
+}
+
+// Find Signal Instance for argument count.
+static PySideSignalInstance *findSignalInstance(PySideSignalInstance *source, int argCount)
+{
+    for (auto *si = source; si != nullptr; si = si->d->next) {
+        if (si->d->argCount == argCount)
+            return si;
+    }
+    return nullptr;
 }
 
 static PyObject *signalInstanceConnect(PyObject *self, PyObject *args, PyObject *kwds)
@@ -459,14 +484,10 @@ static PyObject *signalInstanceConnect(PyObject *self, PyObject *args, PyObject
         return nullptr;
 
     PySideSignalInstance *source = reinterpret_cast<PySideSignalInstance *>(self);
-    if (!source->d) {
-        PyErr_Format(PyExc_RuntimeError, "cannot connect uninitialized SignalInstance");
-        return nullptr;
-    }
-    if (source->deleted) {
-        PyErr_Format(PyExc_RuntimeError, "Signal source has been deleted");
-        return nullptr;
-    }
+    if (!source->d)
+        return PyErr_Format(PyExc_RuntimeError, "cannot connect uninitialized SignalInstance");
+    if (source->deleted)
+        return PyErr_Format(PyExc_RuntimeError, "Signal source has been deleted");
 
     Shiboken::AutoDecRef pyArgs(PyList_New(0));
 
@@ -496,45 +517,32 @@ static PyObject *signalInstanceConnect(PyObject *self, PyObject *args, PyObject
         }
     } else {
         // Check signature of the slot (method or function) to match signal
-        bool matchedSlot = false;
-
-        PySideSignalInstance *it = source;
         const auto args = extractFunctionArgumentsFromSlot(slot);
+        PySideSignalInstance *matchedSlot = nullptr;
 
         if (args.function != nullptr) {
-            qsizetype slotArgs = argCount(args);
-            if (args.isMethod)
-                slotArgs -= 1;
+            auto slotArgRange = argCount(args);
+            if (args.isMethod) {
+                slotArgRange.min -= 1;
+                slotArgRange.max -= 1;
+            }
 
             // Get signature args
-            bool isShortCircuit = false;
-            QStringList argsSignature = PySide::Signal::getArgsFromSignature(it->d->signature,
-                &isShortCircuit);
-            qsizetype signatureArgs = argsSignature.size();
-
             // Iterate the possible types of connection for this signal and compare
             // it with slot arguments
-            if (signatureArgs != slotArgs) {
-                while (it->d->next != nullptr) {
-                    it = it->d->next;
-                    argsSignature = PySide::Signal::getArgsFromSignature(it->d->signature,
-                        &isShortCircuit);
-                    signatureArgs = argsSignature.size();
-                    if (signatureArgs == slotArgs) {
-                        matchedSlot = true;
-                        break;
-                    }
-                }
+            for (int slotArgs = slotArgRange.max;
+                 slotArgs >= slotArgRange.min && matchedSlot == nullptr; --slotArgs) {
+                 matchedSlot = findSignalInstance(source, slotArgs);
             }
         }
 
         // Adding references to pyArgs
         PyList_Append(pyArgs, source->d->source);
 
-        if (matchedSlot) {
+        if (matchedSlot != nullptr) {
             // If a slot matching the same number of arguments was found,
             // include signature to the pyArgs
-            Shiboken::AutoDecRef signature(PySide::Signal::buildQtCompatible(it->d->signature));
+            Shiboken::AutoDecRef signature(PySide::Signal::buildQtCompatible(matchedSlot->d->signature));
             PyList_Append(pyArgs, signature);
         } else {
             // Try the first by default if the slot was not found
@@ -552,10 +560,8 @@ static PyObject *signalInstanceConnect(PyObject *self, PyObject *args, PyObject
         Shiboken::AutoDecRef tupleArgs(PyList_AsTuple(pyArgs));
         Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(source->d->source,
                                                        PySide::PySideName::qtConnect()));
-        if (pyMethod.isNull()) { // PYSIDE-79: check if pyMethod exists.
-            PyErr_SetString(PyExc_RuntimeError, "method 'connect' vanished!");
-            return nullptr;
-        }
+        if (pyMethod.isNull())  // PYSIDE-79: check if pyMethod exists.
+            return PyErr_Format(PyExc_RuntimeError, "method 'connect' vanished!");
         PyObject *result = PyObject_CallObject(pyMethod, tupleArgs);
         if (connection_Check(result))
             return result;
@@ -575,17 +581,13 @@ static int argCountInSignature(const char *signature)
 static PyObject *signalInstanceEmit(PyObject *self, PyObject *args)
 {
     PySideSignalInstance *source = reinterpret_cast<PySideSignalInstance *>(self);
-    if (!source->d) {
-        PyErr_Format(PyExc_RuntimeError, "cannot emit uninitialized SignalInstance");
-        return nullptr;
-    }
+    if (!source->d)
+        return PyErr_Format(PyExc_RuntimeError, "cannot emit uninitialized SignalInstance");
 
     // PYSIDE-2201: Check if the object has vanished meanwhile.
     //              Tried to revive it without exception, but this gives problems.
-    if (source->deleted) {
-        PyErr_Format(PyExc_RuntimeError, "The SignalInstance object was already deleted");
-        return nullptr;
-    }
+    if (source->deleted)
+        return PyErr_Format(PyExc_RuntimeError, "The SignalInstance object was already deleted");
 
     Shiboken::AutoDecRef pyArgs(PyList_New(0));
     int numArgsGiven = PySequence_Fast_GET_SIZE(args);
@@ -645,17 +647,26 @@ static PyObject *signalInstanceGetItem(PyObject *self, PyObject *key)
         message += '"' + data->d->signature + '"';
     }
 
-    PyErr_SetString(PyExc_IndexError, message.constData());
-    return nullptr;
+    return PyErr_Format(PyExc_IndexError, message.constData());
+}
+
+static inline void warnDisconnectFailed(PyObject *aSlot, const QByteArray &signature)
+{
+    if (PyErr_Occurred() != nullptr) { // avoid "%S" invoking str() when an error is set.
+        PyErr_WarnFormat(PyExc_RuntimeWarning, 0, "Failed to disconnect (%s) from signal \"%s\".",
+                         Py_TYPE(aSlot)->tp_name, signature.constData());
+    } else {
+        PyErr_WarnFormat(PyExc_RuntimeWarning, 0, "Failed to disconnect (%S) from signal \"%s\".",
+                         aSlot, signature.constData());
+    }
 }
 
 static PyObject *signalInstanceDisconnect(PyObject *self, PyObject *args)
 {
     auto source = reinterpret_cast<PySideSignalInstance *>(self);
-    if (!source->d) {
-        PyErr_Format(PyExc_RuntimeError, "cannot disconnect uninitialized SignalInstance");
-        return nullptr;
-    }
+    if (!source->d)
+        return PyErr_Format(PyExc_RuntimeError, "cannot disconnect uninitialized SignalInstance");
+
     Shiboken::AutoDecRef pyArgs(PyList_New(0));
 
     PyObject *slot = Py_None;
@@ -696,14 +707,13 @@ static PyObject *signalInstanceDisconnect(PyObject *self, PyObject *args)
         Shiboken::AutoDecRef pyMethod(PyObject_GetAttr(source->d->source,
                                                        PySide::PySideName::qtDisconnect()));
         PyObject *result = PyObject_CallObject(pyMethod, tupleArgs);
-        if (!result || result == Py_True)
-            return result;
-        Py_DECREF(result);
+        if (result != Py_True)
+            warnDisconnectFailed(slot, source->d->signature);
+        return result;
     }
 
-    PyErr_Format(PyExc_RuntimeError, "Failed to disconnect (%S) from signal \"%s\".",
-                 slot, source->d->signature.constData());
-    return nullptr;
+    warnDisconnectFailed(slot, source->d->signature);
+    Py_RETURN_FALSE;
 }
 
 // PYSIDE-68: Supply the missing __get__ function
@@ -738,23 +748,19 @@ static PyObject *signalCall(PyObject *self, PyObject *args, PyObject *kw)
     // The only way calling a signal can succeed (the Python equivalent of C++'s operator() )
     // is when a method with the same name as the signal is attached to an object.
     // An example is QProcess::error() (don't check the docs, but the source code of qprocess.h).
-    if (!signal->homonymousMethod) {
-        PyErr_SetString(PyExc_TypeError, "native Qt signal is not callable");
-        return nullptr;
-    }
-
-    descrgetfunc getDescriptor = Py_TYPE(signal->homonymousMethod)->tp_descr_get;
+    if (!signal->homonymousMethod)
+        return PyErr_Format(PyExc_TypeError, "native Qt signal is not callable");
 
     // Check if there exists a method with the same name as the signal, which is also a static
     // method in C++ land.
-    Shiboken::AutoDecRef homonymousMethod(getDescriptor(signal->homonymousMethod,
-                                                        nullptr, nullptr));
+    Shiboken::AutoDecRef homonymousMethod(PepExt_Type_CallDescrGet(signal->homonymousMethod,
+                                                                   nullptr, nullptr));
     if (PyCFunction_Check(homonymousMethod.object())
             && (PyCFunction_GET_FLAGS(homonymousMethod.object()) & METH_STATIC))
         return PyObject_Call(homonymousMethod, args, kw);
 
     // Assumes homonymousMethod is not a static method.
-    ternaryfunc callFunc = Py_TYPE(signal->homonymousMethod)->tp_call;
+    ternaryfunc callFunc = PepExt_Type_GetCallSlot(Py_TYPE(signal->homonymousMethod));
     return callFunc(homonymousMethod, args, kw);
 }
 
@@ -811,8 +817,8 @@ static PyObject *signalInstanceCall(PyObject *self, PyObject *args, PyObject *kw
         return nullptr;
     }
 
-    descrgetfunc getDescriptor = Py_TYPE(hom)->tp_descr_get;
-    Shiboken::AutoDecRef homonymousMethod(getDescriptor(hom, PySideSignal->d->source, nullptr));
+    Shiboken::AutoDecRef homonymousMethod(PepExt_Type_CallDescrGet(hom, PySideSignal->d->source,
+                                                                   nullptr));
     return PyObject_Call(homonymousMethod, args, kw);
 }
 
@@ -843,7 +849,7 @@ static const char *SignalInstance_SignatureStrings[] = {
     "PySide6.QtCore.SignalInstance.connect(self,slot:object,"
         "type:PySide6.QtCore.Qt.ConnectionType=PySide6.QtCore.Qt.ConnectionType.AutoConnection)"
         "->PySide6.QtCore.QMetaObject.Connection",
-    "PySide6.QtCore.SignalInstance.disconnect(self,slot:object=nullptr)",
+    "PySide6.QtCore.SignalInstance.disconnect(self,slot:object=nullptr)->bool",
     "PySide6.QtCore.SignalInstance.emit(self,*args:typing.Any)",
     nullptr}; // Sentinel
 
@@ -964,9 +970,10 @@ static QByteArray buildSignature(const QByteArray &name, const QByteArray &signa
 
 static PySideSignalData::Signature parseSignature(PyObject *args)
 {
-    PySideSignalData::Signature result{{}, QMetaMethod::Compatibility};
+    PySideSignalData::Signature result{{}, QMetaMethod::Compatibility, 0};
     if (args && (Shiboken::String::check(args) || !PyTuple_Check(args))) {
         result.signature = getTypeName(args);
+        result.argCount = 1;
         return result;
     }
 
@@ -977,6 +984,7 @@ static PySideSignalData::Signature parseSignature(PyObject *args)
             if (!result.signature.isEmpty())
                 result.signature += ',';
             result.signature += typeName;
+            ++result.argCount;
         }
     }
     return result;
@@ -1001,6 +1009,7 @@ static void instanceInitialize(PySideSignalInstance *self, PyObject *name, PySid
     selfPvt->source = source;
     const auto &signature = signal->data->signatures.at(index);
     selfPvt->signature = buildSignature(self->d->signalName, signature.signature);
+    selfPvt->argCount = signature.argCount;
     selfPvt->attributes = signature.attributes;
     selfPvt->homonymousMethod = nullptr;
     if (signal->homonymousMethod) {
@@ -1078,6 +1087,7 @@ PySideSignalInstance *newObjectFromMethod(PyObject *source, const QList<QMetaMet
         // separate SignalName
         selfPvt->signalName = cppName;
         selfPvt->signature = m.methodSignature();
+        selfPvt->argCount = int(m.parameterCount());
         selfPvt->attributes = m.attributes();
         selfPvt->homonymousMethod = nullptr;
         selfPvt->next = nullptr;
@@ -1113,35 +1123,45 @@ static PyObject *buildQtCompatible(const QByteArray &signature)
 void registerSignals(PyTypeObject *pyObj, const QMetaObject *metaObject)
 {
     using Signature = PySideSignalData::Signature;
-    using SignalSigMap = QHash<QByteArray, QList<Signature>>;
-    SignalSigMap signalsFound;
+    struct MetaSignal
+    {
+        QByteArray methodName;
+        QList<Signature> signatures;
+    };
+
+    QList<MetaSignal> signalsFound;
     for (int i = metaObject->methodOffset(), max = metaObject->methodCount(); i < max; ++i) {
         QMetaMethod method = metaObject->method(i);
 
         if (method.methodType() == QMetaMethod::Signal) {
             QByteArray methodName(method.methodSignature());
-            methodName.chop(methodName.size() - methodName.indexOf('('));
-            Signature signature{method.parameterTypes().join(','), {}};
+            methodName.truncate(methodName.indexOf('('));
+            Signature signature{method.parameterTypes().join(','), {},
+                                short(method.parameterCount())};
             if (method.attributes() & QMetaMethod::Cloned)
                 signature.attributes = QMetaMethod::Cloned;
-            signalsFound[methodName] << signature;
+            auto it = std::find_if(signalsFound.begin(), signalsFound.end(),
+                                   [methodName](const MetaSignal &ms)
+                                   { return ms.methodName == methodName; });
+            if (it != signalsFound.end())
+                it->signatures << signature;
+            else
+                signalsFound.append(MetaSignal{methodName, {signature}});
         }
     }
 
-    SignalSigMap::Iterator it = signalsFound.begin();
-    SignalSigMap::Iterator end = signalsFound.end();
-    for (; it != end; ++it) {
+    for (const auto &metaSignal : std::as_const(signalsFound)) {
         PySideSignal *self = PyObject_New(PySideSignal, PySideSignal_TypeF());
         self->data = new PySideSignalData;
-        self->data->signalName = it.key();
+        self->data->signalName = metaSignal.methodName;
         self->homonymousMethod = nullptr;
 
         // Empty signatures comes first! So they will be the default signal signature
-        self->data->signatures = it.value();
+        self->data->signatures = metaSignal.signatures;
         std::stable_sort(self->data->signatures.begin(),
                          self->data->signatures.end(), &compareSignals);
 
-        _addSignalToWrapper(pyObj, it.key(), self);
+        _addSignalToWrapper(pyObj, metaSignal.methodName, self);
         Py_DECREF(reinterpret_cast<PyObject *>(self));
     }
 }
@@ -1167,29 +1187,30 @@ EmitterData getEmitterData(PySideSignalInstance *signal)
     return result;
 }
 
-QStringList getArgsFromSignature(const char *signature, bool *isShortCircuit)
+QByteArrayList getArgsFromSignature(const char *signature, bool *isShortCircuit)
 {
-    QString qsignature = QString::fromLatin1(signature).trimmed();
-    QStringList result;
+    QByteArray qsignature = QByteArray(signature).trimmed();
+    QByteArrayList result;
 
     if (isShortCircuit)
         *isShortCircuit = !qsignature.contains(u'(');
-    if (qsignature.contains(u"()") || qsignature.contains(u"(void)"))
+    if (qsignature.contains("()") || qsignature.contains("(void)"))
         return result;
-    if (qsignature.endsWith(u')')) {
-        const int paren = qsignature.indexOf(u'(');
+    if (qsignature.endsWith(')')) {
+        const auto paren = qsignature.indexOf('(');
         if (paren >= 0) {
             qsignature.chop(1);
             qsignature.remove(0, paren + 1);
             result = qsignature.split(u',');
-            for (QString &type : result)
+            for (auto &type : result)
                 type = type.trimmed();
         }
     }
     return result;
 }
 
-QString getCallbackSignature(const char *signal, QObject *receiver, PyObject *callback, bool encodeName)
+QByteArray getCallbackSignature(const char *signal, QObject *receiver,
+                                PyObject *callback, bool encodeName)
 {
     QByteArray functionName;
     qsizetype numArgs = -1;
@@ -1198,7 +1219,7 @@ QString getCallbackSignature(const char *signal, QObject *receiver, PyObject *ca
     qsizetype useSelf = slotArgs.isMethod ? 1 : 0;
 
     if (slotArgs.function != nullptr) {
-        numArgs = argCount(slotArgs);
+        numArgs = argCount(slotArgs).max;
 #ifdef PYPY_VERSION
     } else if (Py_TYPE(callback) == PepBuiltinMethod_TypePtr) {
         // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction.
@@ -1262,9 +1283,8 @@ QString getCallbackSignature(const char *signal, QObject *receiver, PyObject *ca
         functionName[0] = '_';
         functionName[functionName.size() - 1] = '_';
     }
-    const QString functionNameS = QLatin1String(functionName);
-    QString signature = encodeName ? codeCallbackName(callback, functionNameS) : functionNameS;
-    QStringList args = getArgsFromSignature(signal, &isShortCircuit);
+    QByteArray signature = encodeName ? codeCallbackName(callback, functionName) : functionName;
+    QByteArrayList args = getArgsFromSignature(signal, &isShortCircuit);
 
     if (!isShortCircuit) {
         signature.append(u'(');
@@ -1272,8 +1292,8 @@ QString getCallbackSignature(const char *signal, QObject *receiver, PyObject *ca
             numArgs = std::numeric_limits<qsizetype>::max();
         while (!args.isEmpty() && (args.size() > (numArgs - useSelf)))
             args.removeLast();
-        signature.append(args.join(u','));
-        signature.append(u')');
+        signature.append(args.join(','));
+        signature.append(')');
     }
     return signature;
 }
@@ -1292,21 +1312,21 @@ bool checkQtSignal(const char *signal)
     return true;
 }
 
-QString codeCallbackName(PyObject *callback, const QString &funcName)
+QByteArray codeCallbackName(PyObject *callback, const QByteArray &funcName)
 {
     if (PyMethod_Check(callback)) {
         PyObject *self = PyMethod_GET_SELF(callback);
         PyObject *func = PyMethod_GET_FUNCTION(callback);
-        return funcName + QString::number(quint64(self), 16) + QString::number(quint64(func), 16);
+        return funcName + QByteArray::number(quint64(self), 16) + QByteArray::number(quint64(func), 16);
     }
     // PYSIDE-1523: Handle the compiled case.
     if (PySide::isCompiledMethod(callback)) {
         // Not retaining references inline with what PyMethod_GET_(SELF|FUNC) does.
         Shiboken::AutoDecRef self(PyObject_GetAttr(callback, PySide::PySideName::im_self()));
         Shiboken::AutoDecRef func(PyObject_GetAttr(callback, PySide::PySideName::im_func()));
-        return funcName + QString::number(quint64(self), 16) + QString::number(quint64(func), 16);
+        return funcName + QByteArray::number(quint64(self), 16) + QByteArray::number(quint64(func), 16);
     }
-    return funcName + QString::number(quint64(callback), 16);
+    return funcName + QByteArray::number(quint64(callback), 16);
 }
 
 QByteArray voidType()
index 821a49fa1648adf38674f89e67233c3da3c919de..589fc2c92ef817a54cb400807b684aee2e816842 100644 (file)
@@ -135,7 +135,8 @@ PYSIDE_API bool checkQtSignal(const char *signature);
  * @param   encodeName  Used to specify if the returned signature will be encoded with Qt signal/slot style
  * @return  Return the callback signature
  **/
-PYSIDE_API QString getCallbackSignature(const char *signal, QObject *receiver, PyObject *callback, bool encodeName);
+PYSIDE_API QByteArray getCallbackSignature(const char *signal, QObject *receiver,
+                                           PyObject *callback, bool encodeName);
 
 /**
  * This function parses the signature and then returns a list of argument types.
@@ -145,8 +146,8 @@ PYSIDE_API QString getCallbackSignature(const char *signal, QObject *receiver, P
  * @return  Return true if this is a Qt Signal, otherwise return false
  * @todo    replace return type by QList<QByteArray>
  **/
-QStringList getArgsFromSignature(const char *signature,
-                                 bool *isShortCircuit = nullptr);
+QByteArrayList getArgsFromSignature(const char *signature,
+                                    bool *isShortCircuit = nullptr);
 
 } // namespace PySide::Signal
 
index 8a0feea4cd83d1851d06929cea552aa81aabb135..55a9a7a704ec7182a9440341cb1391f314774ee9 100644 (file)
@@ -15,6 +15,7 @@ struct PySideSignalData
     {
         QByteArray signature; // ','-separated list of parameter types
         unsigned short attributes;
+        short argCount;
     };
 
     QByteArray signalName;
@@ -43,6 +44,7 @@ struct PySideSignalInstancePrivate
     PyObject *homonymousMethod = nullptr;
     PySideSignalInstance *next = nullptr;
     unsigned short attributes = 0;
+    short argCount = 0;
 };
 
 namespace PySide::Signal {
@@ -50,7 +52,7 @@ namespace PySide::Signal {
     void            init(PyObject *module);
     bool            connect(PyObject *source, const char *signal, PyObject *callback);
     QByteArray      getTypeName(PyObject *);
-    QString         codeCallbackName(PyObject *callback, const QString &funcName);
+    QByteArray      codeCallbackName(PyObject *callback, const QByteArray &funcName);
     QByteArray      voidType();
 
 } // namespace PySide::Signal
index 9105fff6a5a165172d406b2a7616550ca89d5c1e..3bddc84c2ba665843407346b50c39c201d0feef3 100644 (file)
@@ -23,6 +23,7 @@ STATIC_STRING_IMPL(fset, "fset")
 STATIC_STRING_IMPL(im_func, "im_func")
 STATIC_STRING_IMPL(im_self, "im_self")
 STATIC_STRING_IMPL(name, "name")
+STATIC_STRING_IMPL(orig_dict, "orig_dict")
 STATIC_STRING_IMPL(parameters, "parameters")
 STATIC_STRING_IMPL(property, "property")
 STATIC_STRING_IMPL(select_id, "select_id")
index 3d00fac68665766b6c6da4da8f8f37dbef7e571d..b4bc6180016f9fe4b0815a41f5e221613696258d 100644 (file)
@@ -19,6 +19,7 @@ PYSIDE_API PyObject *fset();
 PYSIDE_API PyObject *im_func();
 PYSIDE_API PyObject *im_self();
 PYSIDE_API PyObject *name();
+PYSIDE_API PyObject *orig_dict();
 PYSIDE_API PyObject *parameters();
 PYSIDE_API PyObject *property();
 PYSIDE_API PyObject *select_id();
index d3590510453655a213f849128605deeb8308779f..47c2f2c1b972e4994325d79d3742f8f60644f6da 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <pysidemacros.h>
 
-#include <QtCore/QtGlobal>
+#include <QtCore/qtclasshelpermacros.h>
 
 QT_FORWARD_DECLARE_CLASS(QDebug)
 QT_FORWARD_DECLARE_CLASS(QString)
@@ -55,6 +55,15 @@ struct debugPyObject
 
 PYSIDE_API QDebug operator<<(QDebug debug, const debugPyObject &o);
 
+struct debugPyBuffer
+{
+    PYSIDE_API explicit debugPyBuffer(Py_buffer *b) noexcept;
+
+    Py_buffer *m_buffer;
+};
+
+PYSIDE_API QDebug operator<<(QDebug debug, const debugPyBuffer &b);
+
 } //namespace PySide
 
 #endif // PYSIDESTRING_H
index c47c96eb88571598c96d9ccb9c1e8f3987688e42..3c5b759533be038c6f9b43288bb27af99c685fa2 100644 (file)
@@ -132,7 +132,7 @@ static GetReceiverResult getReceiver(QObject *source, const char *signal,
     if (!result.usingGlobalReceiver && result.receiver && result.self) {
         result.callbackSig =
             PySide::Signal::getCallbackSignature(signal, result.receiver, callback,
-                                                 result.usingGlobalReceiver).toLatin1();
+                                                 result.usingGlobalReceiver);
         const QMetaObject *metaObject = result.receiver->metaObject();
         result.slotIndex = metaObject->indexOfSlot(result.callbackSig.constData());
         if (PyMethod_Check(callback) != 0 && result.slotIndex != -1
@@ -158,7 +158,7 @@ static GetReceiverResult getReceiver(QObject *source, const char *signal,
             result.receiver->moveToThread(receiverThread);
         result.callbackSig =
             PySide::Signal::getCallbackSignature(signal, result.receiver, callback,
-                                                 result.usingGlobalReceiver).toLatin1();
+                                                 result.usingGlobalReceiver);
         const QMetaObject *metaObject = result.receiver->metaObject();
         result.slotIndex = metaObject->indexOfSlot(result.callbackSig.constData());
     }
index b4e1bb487c0cbcc64c0057d2175075b7afb28627..557f130e04e9af366b267e8146cdbc876b6a38f0 100644 (file)
 #include <sbkstaticstrings.h>
 #include <sbkerrors.h>
 
+#include <QtCore/QCoreApplication>
 #include <QtCore/QByteArrayView>
 #include <QtCore/QDebug>
 #include <QtCore/QHash>
 #include <QtCore/QScopedPointer>
+#include <QtCore/QTimerEvent>
 
 #include <algorithm>
 #include <limits>
 #include <memory>
 
+using namespace Qt::StringLiterals;
+
 #if QSLOT_CODE != 1 || QSIGNAL_CODE != 2
 #error QSLOT_CODE and/or QSIGNAL_CODE changed! change the hardcoded stuff to the correct value!
 #endif
 #include "globalreceiverv2.h"
 
 static PyObject *metaObjectAttr = nullptr;
-static PyObject *parseArguments(const QList< QByteArray >& paramTypes, void **args);
+static PyObject *parseArguments(const QMetaMethod &method, void **args);
 static bool emitShortCircuitSignal(QObject *source, int signalIndex, PyObject *args);
+
+static bool qAppRunning = false;
+
 static void destroyMetaObject(PyObject *obj)
 {
     void *ptr = PyCapsule_GetPointer(obj, nullptr);
@@ -68,6 +75,29 @@ static const char *metaCallName(QMetaObject::Call call)
     return it != mapping.constEnd() ? it.value() : "<Unknown>";
 }
 
+static QByteArray methodSignature(const QMetaMethod &method)
+{
+    QByteArray result;
+    if (auto *t = method.typeName()) {
+        result += t;
+        result += ' ';
+    }
+    result += method.methodSignature();
+    return result;
+}
+
+static QByteArray msgCannotConvertParameter(const QMetaMethod &method, qsizetype p)
+{
+    return "Cannot call meta function \""_ba + methodSignature(method)
+           + "\" because parameter " + QByteArray::number(p) + " of type \""_ba
+           + method.parameterTypeName(p) + "\" cannot be converted."_ba;
+}
+
+static QByteArray msgCannotConvertReturn(const QMetaMethod &method)
+{
+    return "The return value of \""_ba + methodSignature(method) + "\" cannot be converted."_ba;
+}
+
 namespace PySide {
 
 PyObjectWrapper::PyObjectWrapper()
@@ -199,6 +229,39 @@ using GlobalReceiverV2Map = QHash<PySide::GlobalReceiverKey, GlobalReceiverV2Ptr
 
 using namespace PySide;
 
+// Listen for destroy() of main thread objects and ensure cleanup
+class SignalManagerDestroyListener : public QObject
+{
+    Q_OBJECT
+public:
+    Q_DISABLE_COPY_MOVE(SignalManagerDestroyListener)
+
+    using QObject::QObject;
+
+public Q_SLOTS:
+    void destroyNotify(const QObject *);
+
+protected:
+    void timerEvent(QTimerEvent *event) override;
+
+private:
+    int m_timerId = -1;
+};
+
+void SignalManagerDestroyListener::destroyNotify(const QObject *)
+{
+    if (qAppRunning && m_timerId == -1)
+        m_timerId = startTimer(0);
+}
+
+void SignalManagerDestroyListener::timerEvent(QTimerEvent *event)
+{
+    if (event->timerId() == m_timerId) {
+        killTimer(std::exchange(m_timerId, -1));
+        SignalManager::instance().purgeEmptyGlobalReceivers();
+    }
+}
+
 struct SignalManager::SignalManagerPrivate
 {
     Q_DISABLE_COPY_MOVE(SignalManagerPrivate)
@@ -206,9 +269,9 @@ struct SignalManager::SignalManagerPrivate
     SignalManagerPrivate() noexcept = default;
     ~SignalManagerPrivate() { clear(); }
 
-    void deleteGobalReceiver(const QObject *gr);
+    void deleteGlobalReceiver(const QObject *gr);
     void clear();
-    void purgeEmptyGobalReceivers();
+    void purgeEmptyGlobalReceivers();
 
     GlobalReceiverV2Map m_globalReceivers;
     static SignalManager::QmlMetaCallErrorHandler m_qmlMetaCallErrorHandler;
@@ -217,6 +280,8 @@ struct SignalManager::SignalManagerPrivate
     static int qtPropertyMetacall(QObject *object, QMetaObject::Call call,
                                   int id, void **args);
     static int qtMethodMetacall(QObject *object, int id, void **args);
+
+    QPointer<SignalManagerDestroyListener> m_listener;
 };
 
 SignalManager::QmlMetaCallErrorHandler
@@ -288,8 +353,32 @@ void SignalManager::setQmlMetaCallErrorHandler(QmlMetaCallErrorHandler handler)
     SignalManagerPrivate::m_qmlMetaCallErrorHandler = handler;
 }
 
+static void qAppAboutToQuit()
+{
+    qAppRunning = false;
+    SignalManager::instance().purgeEmptyGlobalReceivers();
+}
+
+static bool isInMainThread(const QObject *o)
+{
+    if (o->isWidgetType() || o->isWindowType() || o->isQuickItemType())
+        return true;
+    auto *app = QCoreApplication::instance();
+    return app != nullptr && app->thread() == o->thread();
+}
+
 QObject *SignalManager::globalReceiver(QObject *sender, PyObject *callback, QObject *receiver)
 {
+    if (m_d->m_listener.isNull() && !QCoreApplication::closingDown()) {
+        if (auto *app = QCoreApplication::instance()) {
+            // The signal manager potentially outlives QCoreApplication, ensure deletion
+            m_d->m_listener = new SignalManagerDestroyListener(app);
+            m_d->m_listener->setObjectName("qt_pyside_signalmanagerdestroylistener");
+            QObject::connect(app, &QCoreApplication::aboutToQuit, qAppAboutToQuit);
+            qAppRunning = true;
+        }
+    }
+
     auto &globalReceivers = m_d->m_globalReceivers;
     const GlobalReceiverKey key = GlobalReceiverV2::key(callback);
     auto it = globalReceivers.find(key);
@@ -297,16 +386,30 @@ QObject *SignalManager::globalReceiver(QObject *sender, PyObject *callback, QObj
         auto gr = std::make_shared<GlobalReceiverV2>(callback, receiver);
         it = globalReceivers.insert(key, gr);
     }
-    if (sender)
+
+    if (sender != nullptr) {
         it.value()->incRef(sender); // create a link reference
 
+        // For main thread-objects, add a notification for destroy (PYSIDE-2646, 2141)
+        if (qAppRunning && !m_d->m_listener.isNull() && isInMainThread(sender)) {
+            QObject::connect(sender, &QObject::destroyed,
+                             m_d->m_listener, &SignalManagerDestroyListener::destroyNotify,
+                             Qt::UniqueConnection);
+        }
+    }
+
     return it.value().get();
 }
 
+void SignalManager::purgeEmptyGlobalReceivers()
+{
+    m_d->purgeEmptyGlobalReceivers();
+}
+
 void SignalManager::notifyGlobalReceiver(QObject *receiver)
 {
     reinterpret_cast<GlobalReceiverV2 *>(receiver)->notify();
-    m_d->purgeEmptyGobalReceivers();
+    purgeEmptyGlobalReceivers();
 }
 
 void SignalManager::releaseGlobalReceiver(const QObject *source, QObject *receiver)
@@ -314,15 +417,15 @@ void SignalManager::releaseGlobalReceiver(const QObject *source, QObject *receiv
     auto gr = static_cast<GlobalReceiverV2 *>(receiver);
     gr->decRef(source);
     if (gr->isEmpty())
-        m_d->deleteGobalReceiver(gr);
+        m_d->deleteGlobalReceiver(gr);
 }
 
-void SignalManager::deleteGobalReceiver(const QObject *gr)
+void SignalManager::deleteGlobalReceiver(const QObject *gr)
 {
-    SignalManager::instance().m_d->deleteGobalReceiver(gr);
+    SignalManager::instance().m_d->deleteGlobalReceiver(gr);
 }
 
-void SignalManager::SignalManagerPrivate::deleteGobalReceiver(const QObject *gr)
+void SignalManager::SignalManagerPrivate::deleteGlobalReceiver(const QObject *gr)
 {
     for (auto it = m_globalReceivers.begin(), end = m_globalReceivers.end(); it != end; ++it) {
         if (it.value().get() == gr) {
@@ -347,7 +450,7 @@ static bool isEmptyGlobalReceiver(const GlobalReceiverV2Ptr &g)
     return g->isEmpty();
 }
 
-void SignalManager::SignalManagerPrivate::purgeEmptyGobalReceivers()
+void SignalManager::SignalManagerPrivate::purgeEmptyGlobalReceivers()
 {
     // Delete repetitively (see comment in clear()).
     while (true) {
@@ -537,34 +640,27 @@ int SignalManager::callPythonMetaMethod(const QMetaMethod &method, void **args,
     Q_ASSERT(pyMethod);
 
     Shiboken::GilState gil;
-    PyObject *pyArguments = nullptr;
-
-    if (isShortCuit){
-        pyArguments = reinterpret_cast<PyObject *>(args[1]);
-    } else {
-        pyArguments = parseArguments(method.parameterTypes(), args);
-    }
+    PyObject *pyArguments = isShortCuit
+        ? reinterpret_cast<PyObject *>(args[1]) : parseArguments(method, args);
 
     if (pyArguments) {
         QScopedPointer<Shiboken::Conversions::SpecificConverter> retConverter;
         const char *returnType = method.typeName();
-        if (returnType && std::strcmp("", returnType) && std::strcmp("void", returnType)) {
+        if (returnType != nullptr && returnType[0] != 0 && std::strcmp("void", returnType) != 0) {
             retConverter.reset(new Shiboken::Conversions::SpecificConverter(returnType));
             if (!retConverter->isValid()) {
-                PyErr_Format(PyExc_RuntimeError, "Can't find converter for '%s' to call Python meta method.", returnType);
+                PyErr_SetString(PyExc_RuntimeError, msgCannotConvertReturn(method).constData());
                 return -1;
             }
         }
 
         Shiboken::AutoDecRef retval(PyObject_CallObject(pyMethod, pyArguments));
 
-        if (!isShortCuit && pyArguments){
+        if (!isShortCuit && pyArguments)
             Py_DECREF(pyArguments);
-        }
 
-        if (!retval.isNull() && retval != Py_None && !PyErr_Occurred() && retConverter) {
+        if (!retval.isNull() && retval != Py_None && !PyErr_Occurred() && retConverter)
             retConverter->toCpp(retval, args[0]);
-        }
     }
 
     return -1;
@@ -708,22 +804,22 @@ const QMetaObject *SignalManager::retrieveMetaObject(PyObject *self)
     return builder->update();
 }
 
-static PyObject *parseArguments(const QList<QByteArray>& paramTypes, void **args)
+static PyObject *parseArguments(const QMetaMethod &method, void **args)
 {
+    const auto &paramTypes = method.parameterTypes();
     const qsizetype argsSize = paramTypes.size();
     PyObject *preparedArgs = PyTuple_New(argsSize);
 
     for (qsizetype i = 0; i < argsSize; ++i) {
         void *data = args[i+1];
-        const char *dataType = paramTypes[i].constData();
-        Shiboken::Conversions::SpecificConverter converter(dataType);
-        if (converter) {
-            PyTuple_SET_ITEM(preparedArgs, i, converter.toPython(data));
-        } else {
-            PyErr_Format(PyExc_TypeError, "Can't call meta function because I have no idea how to handle %s", dataType);
+        auto param = paramTypes.at(i);
+        Shiboken::Conversions::SpecificConverter converter(param.constData());
+        if (!converter) {
+            PyErr_SetString(PyExc_TypeError, msgCannotConvertParameter(method, i).constData());
             Py_DECREF(preparedArgs);
             return nullptr;
         }
+        PyTuple_SET_ITEM(preparedArgs, i, converter.toPython(data));
     }
     return preparedArgs;
 }
@@ -734,3 +830,5 @@ static bool emitShortCircuitSignal(QObject *source, int signalIndex, PyObject *a
     source->qt_metacall(QMetaObject::InvokeMetaMethod, signalIndex, signalArgs);
     return true;
 }
+
+#include "signalmanager.moc"
index df47c33b68128d1841b8024e3400dbebb6497d29..c531d663022baf7aca8ef4b447411f112b78575e 100644 (file)
@@ -78,11 +78,12 @@ public:
 
     // Disconnect all signals managed by Globalreceiver
     void clear();
+    void purgeEmptyGlobalReceivers();
 
     // Utility function to call a python method usign args received in qt_metacall
     static int callPythonMetaMethod(const QMetaMethod& method, void** args, PyObject* obj, bool isShortCuit);
 
-    static void deleteGobalReceiver(const QObject *globalReceiver);
+    static void deleteGlobalReceiver(const QObject *globalReceiver);
 
 private:
     struct SignalManagerPrivate;
index 930358d77754b7a8d13b1dfcaf030d1707519ef7..d484257e2613d90777de7bed639175ad4c818d6c 100644 (file)
@@ -14,7 +14,6 @@
 #include <signature.h>
 #include <sbkstring.h>
 
-#include <QtCore/QtGlobal>
 #include <QtQml/qqml.h>
 
 #include <algorithm>
index 9365b68d3db478bfeeff93432ac61889d537d7eb..96f788268d93487d14942e373f2b21cc2b2df5ea 100644 (file)
@@ -8,7 +8,7 @@
 
 #include "pysideqmlmacros.h"
 
-#include <QtCore/QtGlobal>
+#include <QtCore/qtconfigmacros.h>
 
 QT_FORWARD_DECLARE_CLASS(QObject)
 
index 0147948540388d93657b0d3830c218c854a12495..23543d589d8bceab79eead614b3b3d7e8db4be7b 100644 (file)
@@ -12,7 +12,6 @@
 #include <signature.h>
 #include <sbkstring.h>
 
-#include <QtCore/QtGlobal>
 #include <QtQml/qqml.h>
 
 // The QmlExtended decorator modifies QmlElement to register an extension.
index f9cc4f44d105654d9323d520e8df3ffa5386cbf5..18d39d121142c3c3ddf403171bf2c92d3759c254 100644 (file)
@@ -11,7 +11,6 @@
 #include <signature.h>
 #include <sbkstring.h>
 
-#include <QtCore/QtGlobal>
 #include <QtCore/QDebug>
 
 // The QmlForeign decorator modifies QmlElement to create a different type
index a6f9f01939a3dcf96964e3165a63dfdb74ac01a9..75bb5af9696e76b39fdad9a13304bf9960074e6a 100644 (file)
@@ -5,6 +5,7 @@
 #include "pysideqmlregistertype_p.h"
 
 #include <shiboken.h>
+#include <pep384ext.h>
 #include <signature.h>
 
 #include <pysideproperty.h>
@@ -33,7 +34,7 @@ extern "C"
 
 static PyObject *propList_tp_new(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
 {
-    PySideProperty *me = reinterpret_cast<PySideProperty *>(subtype->tp_alloc(subtype, 0));
+    auto *me = PepExt_TypeCallAlloc<PySideProperty>(subtype, 0);
     me->d = new QmlListPropertyPrivate;
     return reinterpret_cast<PyObject *>(me);
 }
@@ -168,7 +169,7 @@ qsizetype propListCount(QQmlListProperty<QObject> *propList)
         return 0;
     }
 
-    int cppResult = 0;
+    qsizetype cppResult = 0;
     auto *converter = Shiboken::Conversions::PrimitiveTypeConverter<qsizetype>();
     if (auto *pythonToCpp = Shiboken::Conversions::isPythonToCppConvertible(converter, retVal))
         pythonToCpp(retVal, &cppResult);
index 8e1381a4e04e18c28e27f19eacab1a136a8f29f6..63cefedb5dfbf35eba729e351dc0caffd8ded3e2 100644 (file)
@@ -45,7 +45,7 @@ std::optional<int> qmlMetaCallErrorHandler(QObject *object)
     // PYSIDE-464: The error is only valid before PyErr_Restore,
     // PYSIDE-464: therefore we take local copies.
     Shiboken::AutoDecRef objStr(PyObject_Str(errValue));
-    const QString errString = QLatin1String(Shiboken::String::toCString(objStr));
+    const QString errString = QString::fromUtf8(Shiboken::String::toCString(objStr));
     const bool isSyntaxError = errType == PyExc_SyntaxError;
     const bool isTypeError = errType == PyExc_TypeError;
     PyErr_Restore(errType, errValue, errTraceback);
index 745ade51eaa1df0119198e6ec3c9b3a5d1582ecc..fcbb6395db46f603d9efa1f62effbb4626e681be 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <optional>
 
-#include <QtCore/QtGlobal>
+#include <QtCore/qtclasshelpermacros.h>
 
 QT_FORWARD_DECLARE_CLASS(QObject)
 
index f296380175853fa9559126486a9ab794834c3c9e..faf3e4116602abc7caf269364561fbfed6ac62fe 100644 (file)
@@ -2,15 +2,12 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "pysideqmlnamedelement_p.h"
-#include "pysideqmltypeinfo_p.h"
 #include <pysideclassdecorator_p.h>
 #include <pysideqmlregistertype_p.h>
 
 #include <shiboken.h>
 #include <signature.h>
 
-#include <QtCore/QtGlobal>
-
 class PySideQmlNamedElementPrivate : public PySide::ClassDecorator::StringDecoratorPrivate
 {
 public:
@@ -31,7 +28,7 @@ PyObject *PySideQmlNamedElementPrivate::tp_call(PyObject *self, PyObject *args,
         return nullptr;
 
     auto *data = DecoratorPrivate::get<PySideQmlNamedElementPrivate>(self);
-    auto *result = PySide::Qml::qmlNamedElementMacro(klass, data->string().c_str());
+    auto *result = PySide::Qml::qmlNamedElementMacro(klass, data->string());
     Py_XINCREF(result);
     return result;
 }
index 1208220ca5a8bfe3ffcad61606e7a256e31225e2..4ccd459d5a1f603a778038b6a8265839de9b686c 100644 (file)
@@ -6,8 +6,10 @@
 #include "pysideqmltypeinfo_p.h"
 #include "pysideqmlattached_p.h"
 #include "pysideqmlextended_p.h"
+#include "pysideqmluncreatable.h"
 
 #include <limits>
+#include <optional>
 
 // shiboken
 #include <shiboken.h>
@@ -16,6 +18,7 @@
 // pyside
 #include <pyside.h>
 #include <pysideqobject.h>
+#include <pysideclassinfo.h>
 #include <pyside_p.h>
 
 #include <QtCore/QMutex>
 #include <QtQml/QJSValue>
 #include <QtQml/QQmlListProperty>
 #include <private/qqmlmetatype_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+
+#include <memory>
+
+using namespace Qt::StringLiterals;
 
 static PySide::Qml::QuickRegisterItemFunction quickRegisterItemFunction = nullptr;
 
+static const auto qmlElementKey = "QML.Element"_ba;
+
 static void createInto(void *memory, void *type)
 {
     QMutexLocker locker(&PySide::nextQObjectMemoryAddrMutex());
@@ -85,25 +95,112 @@ static inline bool isQmlParserStatus(const QMetaObject *o)
     return inheritsFrom(o, "QPyQmlParserStatus");
 }
 
-namespace PySide::Qml {
+static QByteArray getGlobalString(const char *name)
+{
+    PyObject *globalVar = PyDict_GetItemString(PyEval_GetGlobals(), name);
 
-int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
-                    int versionMinor, const char *qmlName, const char *noCreationReason,
-                    bool creatable)
+    if (globalVar == nullptr || PyUnicode_Check(globalVar) == 0)
+        return {};
+
+    const char *stringValue = _PepUnicode_AsString(globalVar);
+    return stringValue != nullptr ? QByteArray(stringValue) : QByteArray{};
+}
+
+static int getGlobalInt(const char *name)
 {
-    using namespace Shiboken;
+    PyObject *globalVar = PyDict_GetItemString(PyEval_GetGlobals(), name);
 
-    PyTypeObject *qobjectType = qObjectType();
+    if (globalVar == nullptr || PyLong_Check(globalVar) == 0)
+        return -1;
 
-    PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
-    if (!PySequence_Contains(pyObjType->tp_mro, reinterpret_cast<PyObject *>(qobjectType))) {
-        PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.",
-                     qobjectType->tp_name, pyObjType->tp_name);
+    long value = PyLong_AsLong(globalVar);
+
+    if (value > std::numeric_limits<int>::max() || value < std::numeric_limits<int>::min())
         return -1;
+
+    return value;
+}
+
+struct ImportData
+{
+    QByteArray importName;
+    int majorVersion = 0;
+    int minorVersion = 0;
+
+    QTypeRevision toTypeRevision() const;
+};
+
+QTypeRevision ImportData::toTypeRevision() const
+{
+    return QTypeRevision::fromVersion(majorVersion, minorVersion);
+}
+
+std::optional<ImportData> getGlobalImportData(const char *decoratorName)
+{
+    ImportData result{getGlobalString("QML_IMPORT_NAME"),
+                      getGlobalInt("QML_IMPORT_MAJOR_VERSION"),
+                      getGlobalInt("QML_IMPORT_MINOR_VERSION")};
+
+    if (result.importName.isEmpty()) {
+        PyErr_Format(PyExc_TypeError, "You need specify QML_IMPORT_NAME in order to use %s.",
+                     decoratorName);
+        return {};
     }
 
-    const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType);
-    Q_ASSERT(metaObject);
+    if (result.majorVersion == -1) {
+        PyErr_Format(PyExc_TypeError, "You need specify QML_IMPORT_MAJOR_VERSION in order to use %s.",
+                     decoratorName);
+        return {};
+    }
+
+    // Specifying a minor version is optional
+    if (result.minorVersion == -1)
+        result.minorVersion = 0;
+    return result;
+}
+
+static PyTypeObject *checkTypeObject(PyObject *pyObj, const char *what)
+{
+    if (PyType_Check(pyObj) == 0) {
+        PyErr_Format(PyExc_TypeError, "%s can only be used for classes.", what);
+        return nullptr;
+    }
+    return reinterpret_cast<PyTypeObject *>(pyObj);
+}
+
+static bool setClassInfo(PyTypeObject *type, const QByteArray &key, const QByteArray &value)
+{
+    if (!PySide::ClassInfo::setClassInfo(type, key, value)) {
+        PyErr_Format(PyExc_TypeError, "Setting class info \"%s\" to \"%s\" on \"%s\" failed.",
+                     key.constData(), value.constData(), type->tp_name);
+        return false;
+    }
+    return true;
+}
+
+static inline bool setSingletonClassInfo(PyTypeObject *type)
+{
+    return setClassInfo(type, "QML.Singleton"_ba, "true"_ba);
+}
+
+static QQmlCustomParser *defaultCustomParserFactory()
+{
+    return nullptr;
+}
+
+namespace PySide::Qml {
+
+// Modern (6.7) type registration using RegisterTypeAndRevisions
+// and information set to QMetaClassInfo.
+static int qmlRegisterType(PyObject *pyObj,
+                           const ImportData &importData,
+                           const QMetaObject *metaObject,
+                           const QMetaObject *classInfoMetaObject = nullptr)
+{
+    PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
+
+    if (classInfoMetaObject == nullptr)
+        classInfoMetaObject = metaObject;
 
     // Register as simple QObject rather than Qt Quick item.
     // Incref the type object, don't worry about decref'ing it because
@@ -121,26 +218,27 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
     const auto attachedInfo = qmlAttachedInfo(pyObjType, typeInfo);
     const auto extendedInfo = qmlExtendedInfo(pyObj, typeInfo);
 
-    QQmlPrivate::RegisterType type {
+    QList<int> ids;
+    QQmlPrivate::RegisterTypeAndRevisions type {
         QQmlPrivate::RegisterType::StructVersion::Base, // structVersion
         typeId, listId, objectSize,
-        creatable ? createInto : nullptr, // create
+        createInto, // create
         pyObj, // userdata
-        QString::fromUtf8(noCreationReason),
         nullptr, // createValueType (Remove in Qt 7)
-        uri,
-        QTypeRevision::fromVersion(versionMajor, versionMinor), // version
-        qmlName, // elementName
+        importData.importName.constData(),
+        importData.toTypeRevision(), // version
         metaObject,
+        classInfoMetaObject,
         attachedInfo.factory, // attachedPropertiesFunction
         attachedInfo.metaObject, // attachedPropertiesMetaObject
         0, 0, 0, // parserStatusCast, valueSourceCast, valueInterceptorCast
         extendedInfo.factory, // extensionObjectCreate
         extendedInfo.metaObject, // extensionMetaObject
-        nullptr, // customParser
-        {}, // revision
+        defaultCustomParserFactory, // customParser
+        &ids, // qmlTypeIds
         0, // finalizerCast
-        QQmlPrivate::ValueTypeCreationMethod::None // creationMethod
+        false, // forceAnonymous
+        {} // listMetaSequence
     };
 
     // Allow registering Qt Quick items.
@@ -160,39 +258,245 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
                 QQmlPrivate::StaticCastSelector<QObject, QQmlPropertyValueInterceptor>::cast();
     }
 
-    int qmlTypeId = QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+    QQmlPrivate::qmlregister(QQmlPrivate::TypeAndRevisionsRegistration, &type);
+    const int qmlTypeId = ids.value(0, -1);
     if (qmlTypeId == -1) {
         PyErr_Format(PyExc_TypeError, "QML meta type registration of \"%s\" failed.",
-                     qmlName);
+                     typeName.constData());
     }
     return qmlTypeId;
 }
 
-int qmlRegisterSingletonType(PyObject *pyObj, const char *uri, int versionMajor,
-                             int versionMinor, const char *qmlName, PyObject *callback,
-                             bool isQObject, bool hasCallback)
+static int qmlRegisterType(PyObject *pyObj, PyObject *pyClassInfoObj,
+                           const ImportData &importData)
 {
-    using namespace Shiboken;
+    PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
+    if (!isQObjectDerived(pyObjType, true))
+        return -1;
 
-    if (hasCallback) {
-        if (!PyCallable_Check(callback)) {
-            PyErr_Format(PyExc_TypeError, "Invalid callback specified.");
-            return -1;
-        }
+    const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType);
+    Q_ASSERT(metaObject);
+    const QMetaObject *classInfoMetaObject = pyObj == pyClassInfoObj
+        ? metaObject : PySide::retrieveMetaObject(pyClassInfoObj);
+    return qmlRegisterType(pyObj, importData, metaObject, classInfoMetaObject);
+}
 
-        AutoDecRef funcCode(PyObject_GetAttrString(callback, "__code__"));
-        AutoDecRef argCount(PyObject_GetAttrString(funcCode, "co_argcount"));
+// Legacy (pre 6.7) compatibility helper for the free register functions.
+int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int versionMinor,
+                    const char *qmlName, const char *noCreationReason,
+                    bool creatable)
+{
+    auto *type = checkTypeObject(pyObj, "qmlRegisterType()");
+    if (type == nullptr || !PySide::isQObjectDerived(type, true))
+        return -1;
 
-        int count = PyLong_AsLong(argCount);
+    const QMetaObject *metaObject = PySide::retrieveMetaObject(type);
+    Q_ASSERT(metaObject);
 
-        if (count != 1) {
-            PyErr_Format(PyExc_TypeError, "Callback has a bad parameter count.");
-            return -1;
+    // PYSIDE-2709: Use a separate QMetaObject for the class information
+    // as modifying metaObject breaks inheritance.
+    QMetaObjectBuilder classInfobuilder(&QObject::staticMetaObject);
+    classInfobuilder.addClassInfo(qmlElementKey, qmlName);
+    if (!creatable)
+        setUncreatableClassInfo(&classInfobuilder, noCreationReason);
+    auto *classInfoMetaObject = classInfobuilder.toMetaObject();
+
+    const int qmlTypeId = qmlRegisterType(pyObj, {uri, versionMajor, versionMinor},
+                                          metaObject, classInfoMetaObject);
+    free(classInfoMetaObject);
+    return qmlTypeId;
+}
+
+// Singleton helpers
+
+// Check the arguments of a singleton callback (C++: "QJSValue cb(QQmlEngine *, QJSEngine *)",
+// but we drop the QJSEngine since it will be the same as QQmlEngine when the latter exists.
+static bool checkSingletonCallback(PyObject *callback)
+{
+    if (callback == nullptr) {
+        PyErr_SetString(PyExc_TypeError, "No callback specified.");
+        return false;
+    }
+    if (PyCallable_Check(callback) == 0) {
+        PyErr_Format(PyExc_TypeError, "Invalid callback specified (%S).", callback);
+        return false;
+    }
+    Shiboken::AutoDecRef funcCode(PyObject_GetAttrString(callback, "__code__"));
+    if (funcCode.isNull()) {
+        PyErr_Format(PyExc_TypeError, "Cannot retrieve code of callback (%S).", callback);
+        return false;
+    }
+    Shiboken::AutoDecRef argCountAttr(PyObject_GetAttrString(funcCode, "co_argcount"));
+    const int argCount = PyLong_AsLong(argCountAttr.object());
+    if (argCount != 1) {
+        PyErr_Format(PyExc_TypeError, "Callback (%S) has %d parameter(s), expected one.",
+                     callback, argCount);
+        return false;
+    }
+
+    return true;
+}
+
+// Shared data of a singleton creation callback which dereferences an object on
+// destruction.
+class SingletonQObjectCreationSharedData
+{
+public:
+    Q_DISABLE_COPY_MOVE(SingletonQObjectCreationSharedData)
+
+    SingletonQObjectCreationSharedData(PyObject *cb, PyObject *ref = nullptr) noexcept :
+        callable(cb), reference(ref)
+    {
+        Py_XINCREF(ref);
+    }
+
+    // FIXME: Currently, the QML registration data are in global static variables
+    // and thus cleaned up after Python terminates. Once they are cleaned up
+    // by the QML engine, the code can be activated for proper cleanup of the references.
+   ~SingletonQObjectCreationSharedData()
+#if 0 //
+    ~SingletonQObjectCreationSharedData()
+    {
+        if (reference != nullptr) {
+            Shiboken::GilState gil;
+            Py_DECREF(reference);
         }
+    }
+#else
+        = default;
+#endif
+
+    PyObject *callable{}; // Callback, static method or type object to  be invoked.
+    PyObject *reference{}; // Object to dereference when going out scope
+};
+
+// Base class for QML singleton creation callbacks with helper for error checking.
+class SingletonQObjectCreationBase
+{
+protected:
+    explicit SingletonQObjectCreationBase(PyObject *cb, PyObject *ref = nullptr) :
+        m_data(std::make_shared<SingletonQObjectCreationSharedData>(cb, ref))
+    {
+    }
+
+    static QObject *handleReturnValue(PyObject *retVal);
+
+    std::shared_ptr<SingletonQObjectCreationSharedData> data() const { return m_data; }
+
+private:
+    std::shared_ptr<SingletonQObjectCreationSharedData> m_data;
+};
+
+QObject *SingletonQObjectCreationBase::handleReturnValue(PyObject *retVal)
+{
+    using Shiboken::Conversions::isPythonToCppPointerConvertible;
+    // Make sure the callback returns something we can convert, else the entire application will crash.
+    if (retVal == nullptr) {
+        PyErr_Format(PyExc_TypeError, "Callback returns 0 value.");
+        return nullptr;
+    }
+    if (isPythonToCppPointerConvertible(qObjectType(), retVal) == nullptr) {
+        PyErr_Format(PyExc_TypeError, "Callback returns invalid value (%S).", retVal);
+        return nullptr;
+    }
+
+    QObject *obj = nullptr;
+    Shiboken::Conversions::pythonToCppPointer(qObjectType(), retVal, &obj);
+    return obj;
+}
+
+// QML singleton creation callback by invoking a type object
+class SingletonQObjectFromTypeCreation : public SingletonQObjectCreationBase
+{
+public:
+    explicit SingletonQObjectFromTypeCreation(PyObject *typeObj) :
+        SingletonQObjectCreationBase(typeObj, typeObj) {}
+
+    QObject *operator ()(QQmlEngine *, QJSEngine *) const
+    {
+        Shiboken::GilState gil;
+        Shiboken::AutoDecRef args(PyTuple_New(0));
+        PyObject *retVal = PyObject_CallObject(data()->callable, args);
+        QObject *result = handleReturnValue(retVal);
+        if (result == nullptr)
+            Py_XDECREF(retVal);
+        return result;
+    }
+};
+
+// QML singleton creation by invoking a callback, passing QQmlEngine. Keeps a
+// references to the the callback.
+class SingletonQObjectCallbackCreation : public SingletonQObjectCreationBase
+{
+public:
+    explicit SingletonQObjectCallbackCreation(PyObject *callback) :
+        SingletonQObjectCreationBase(callback, callback) {}
+    explicit SingletonQObjectCallbackCreation(PyObject *callback, PyObject *ref) :
+        SingletonQObjectCreationBase(callback, ref) {}
+
+    QObject *operator ()(QQmlEngine *engine, QJSEngine *) const
+    {
+        Shiboken::GilState gil;
+        Shiboken::AutoDecRef args(PyTuple_New(1));
+        PyTuple_SET_ITEM(args, 0,
+                         Shiboken::Conversions::pointerToPython(qQmlEngineType(), engine));
+        PyObject *retVal = PyObject_CallObject(data()->callable, args);
+        QObject *result = handleReturnValue(retVal);
+        if (result == nullptr)
+            Py_XDECREF(retVal);
+        return result;
+    }
+};
+
+using SingletonQObjectCreation = std::function<QObject*(QQmlEngine *, QJSEngine *)>;
+
+// Modern (6.7) singleton type registration using RegisterSingletonTypeAndRevisions
+// and information set to QMetaClassInfo (QObject only pending QTBUG-110467).
+static int qmlRegisterSingletonTypeV2(PyObject *pyObj, PyObject *pyClassInfoObj,
+                                      const ImportData &importData,
+                                      const SingletonQObjectCreation &callback)
+{
+    PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
+    if (!isQObjectDerived(pyObjType, true))
+        return -1;
 
-        // Make sure the callback never gets deallocated
-        Py_INCREF(callback);
+    const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType);
+    Q_ASSERT(metaObject);
+    const QMetaObject *classInfoMetaObject = pyObj == pyClassInfoObj
+        ? metaObject : PySide::retrieveMetaObject(pyClassInfoObj);
+
+    QList<int> ids;
+    QQmlPrivate::RegisterSingletonTypeAndRevisions type {
+        QQmlPrivate::RegisterType::StructVersion::Base, // structVersion
+        importData.importName.constData(),
+        importData.toTypeRevision(), // version
+        callback, // qObjectApi,
+        metaObject,
+        classInfoMetaObject,
+        QMetaType(QMetaType::QObjectStar), // typeId
+        nullptr, // extensionMetaObject
+        nullptr, // extensionObjectCreate
+        &ids
+    };
+
+    QQmlPrivate::qmlregister(QQmlPrivate::SingletonAndRevisionsRegistration, &type);
+    const int qmlTypeId = ids.value(0, -1);
+    if (qmlTypeId == -1) {
+        PyErr_Format(PyExc_TypeError, "Singleton QML meta type registration of \"%s\" failed.",
+                     pyObjType->tp_name);
     }
+    return qmlTypeId;
+}
+
+// Legacy (pre 6.7) singleton type registration using RegisterSingletonType
+// for QObject and value types. Still used by qmlRegisterSingletonType()
+// for the hypothetical case of a value type.
+static int qmlRegisterSingletonType(PyObject *pyObj, const ImportData &importData,
+                                    const char *qmlName, PyObject *callback,
+                                    bool isQObject, bool hasCallback)
+{
+    if (hasCallback && !checkSingletonCallback(callback))
+        return -1;
 
     const QMetaObject *metaObject = nullptr;
 
@@ -202,18 +506,14 @@ int qmlRegisterSingletonType(PyObject *pyObj, const char *uri, int versionMajor,
         if (!isQObjectDerived(pyObjType, true))
             return -1;
 
-        // If we don't have a callback we'll need the pyObj to stay allocated indefinitely
-        if (!hasCallback)
-            Py_INCREF(pyObj);
-
         metaObject = PySide::retrieveMetaObject(pyObjType);
         Q_ASSERT(metaObject);
     }
 
     QQmlPrivate::RegisterSingletonType type {
         QQmlPrivate::RegisterType::StructVersion::Base, // structVersion
-        uri,
-        QTypeRevision::fromVersion(versionMajor, versionMinor), // version
+        importData.importName.constData(),
+        importData.toTypeRevision(), // version
         qmlName, // typeName
         {}, // scriptApi
         {}, // qObjectApi
@@ -228,36 +528,15 @@ int qmlRegisterSingletonType(PyObject *pyObj, const char *uri, int versionMajor,
         // FIXME: Fix this to assign new type ids each time.
         type.typeId = QMetaType(QMetaType::QObjectStar);
 
-        type.qObjectApi =
-            [callback, pyObj, hasCallback](QQmlEngine *engine, QJSEngine *) -> QObject * {
-                Shiboken::GilState gil;
-                AutoDecRef args(PyTuple_New(hasCallback ? 1 : 0));
-
-                if (hasCallback) {
-                    PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython(
-                                     qQmlEngineType(), engine));
-                }
-
-                AutoDecRef retVal(PyObject_CallObject(hasCallback ? callback : pyObj, args));
-
-                // Make sure the callback returns something we can convert, else the entire application will crash.
-                if (retVal.isNull() ||
-                    Conversions::isPythonToCppPointerConvertible(qObjectType(), retVal) == nullptr) {
-                    PyErr_Format(PyExc_TypeError, "Callback returns invalid value.");
-                    return nullptr;
-                }
-
-                QObject *obj = nullptr;
-                Conversions::pythonToCppPointer(qObjectType(), retVal, &obj);
-
-                if (obj != nullptr)
-                    Py_INCREF(retVal);
-
-                return obj;
-            };
+        if (hasCallback)
+            type.qObjectApi = SingletonQObjectCallbackCreation(callback);
+        else
+            type.qObjectApi = SingletonQObjectFromTypeCreation(pyObj);
     } else {
         type.scriptApi =
             [callback](QQmlEngine *engine, QJSEngine *) -> QJSValue {
+                using namespace Shiboken;
+
                 Shiboken::GilState gil;
                 AutoDecRef args(PyTuple_New(1));
 
@@ -287,9 +566,19 @@ int qmlRegisterSingletonType(PyObject *pyObj, const char *uri, int versionMajor,
     return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &type);
 }
 
-int qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri, int versionMajor,
-                                 int versionMinor, const char *qmlName,
-                                 PyObject *instanceObject)
+// Legacy (pre 6.7) compatibility helper for the free register functions.
+int qmlRegisterSingletonType(PyObject *pyObj,const char *uri,
+                             int versionMajor, int versionMinor, const char *qmlName,
+                             PyObject *callback, bool isQObject, bool hasCallback)
+{
+    return qmlRegisterSingletonType(pyObj, {uri, versionMajor, versionMinor}, qmlName,
+                                    callback, isQObject, hasCallback);
+}
+
+// Modern (6.7) singleton instance registration using RegisterSingletonTypeAndRevisions
+// and information set to QMetaClassInfo (QObject only).
+static int qmlRegisterSingletonInstance(PyObject *pyObj, const ImportData &importData,
+                                        PyObject *instanceObject)
 {
     using namespace Shiboken;
 
@@ -312,169 +601,140 @@ int qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri, int versionMa
     const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType);
     Q_ASSERT(metaObject);
 
-    // FIXME: Fix this to assign new type ids each time.
-    const QMetaType typeId = QMetaType(QMetaType::QObjectStar);
-
-    QQmlPrivate::RegisterSingletonType type {
+    QList<int> ids;
+    QQmlPrivate::RegisterSingletonTypeAndRevisions type {
         QQmlPrivate::RegisterType::StructVersion::Base, // structVersion
-        uri,
-        QTypeRevision::fromVersion(versionMajor, versionMinor), // version
-        qmlName, // typeName
-        {}, // scriptApi
-        registrationFunctor, // qObjectApi
-        metaObject, // instanceMetaObject
-        typeId,
+        importData.importName.constData(),
+        importData.toTypeRevision(), // version
+        registrationFunctor, // qObjectApi,
+        metaObject,
+        metaObject, // classInfoMetaObject
+        QMetaType(QMetaType::QObjectStar), // typeId
         nullptr, // extensionMetaObject
         nullptr, // extensionObjectCreate
-        {} // revision
+        &ids
     };
 
-    return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &type);
-}
-
-} // namespace PySide::Qml
-
-static std::string getGlobalString(const char *name)
-{
-    using Shiboken::AutoDecRef;
-
-    PyObject *globals = PyEval_GetGlobals();
-
-    AutoDecRef pyName(Py_BuildValue("s", name));
-
-    PyObject *globalVar = PyDict_GetItem(globals, pyName);
-
-    if (globalVar == nullptr || !PyUnicode_Check(globalVar))
-        return "";
-
-    const char *stringValue = _PepUnicode_AsString(globalVar);
-    return stringValue != nullptr ? stringValue : "";
+    QQmlPrivate::qmlregister(QQmlPrivate::SingletonAndRevisionsRegistration, &type);
+    return ids.value(0, -1);
 }
 
-static int getGlobalInt(const char *name)
+// Legacy (pre 6.7) compatibility helper for the free register functions.
+int qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri, int versionMajor,
+                                 int versionMinor, const char *qmlName,
+                                 PyObject *instanceObject)
 {
-    using Shiboken::AutoDecRef;
-
-    PyObject *globals = PyEval_GetGlobals();
-
-    AutoDecRef pyName(Py_BuildValue("s", name));
-
-    PyObject *globalVar = PyDict_GetItem(globals, pyName);
-
-    if (globalVar == nullptr || !PyLong_Check(globalVar))
+    auto *type = checkTypeObject(pyObj, "qmlRegisterSingletonInstance()");
+    if (type == nullptr || !setClassInfo(type, qmlElementKey, qmlName)
+        || !setSingletonClassInfo(type)) {
         return -1;
-
-    long value = PyLong_AsLong(globalVar);
-
-    if (value > std::numeric_limits<int>::max() || value < std::numeric_limits<int>::min())
-        return -1;
-
-    return value;
+    }
+    return qmlRegisterSingletonInstance(pyObj, {uri, versionMajor, versionMinor},
+                                        instanceObject);
 }
 
+} // namespace PySide::Qml
+
 enum class RegisterMode {
     Normal,
-    Anonymous,
-    Uncreatable,
     Singleton
 };
 
-static PyObject *qmlElementMacroHelper(PyObject *pyObj,
-                                       const char *decoratorName,
-                                       const char *typeName = nullptr,
-                                       RegisterMode mode = RegisterMode::Normal,
-                                       const char *noCreationReason = nullptr)
+namespace PySide::Qml {
+
+// Check for a static create() method on a decorated singleton.
+// Might set a Python error if the check fails.
+static std::optional<SingletonQObjectCreation>
+    singletonCreateMethod(PyTypeObject *pyObjType)
 {
-    if (!PyType_Check(pyObj)) {
-        PyErr_Format(PyExc_TypeError, "This decorator can only be used on classes.");
-        return nullptr;
+    Shiboken::AutoDecRef tpDict(PepType_GetDict(pyObjType));
+    auto *create = PyDict_GetItemString(tpDict.object(), "create");
+    // Method decorated by "@staticmethod"
+    if (create == nullptr || std::strcmp(Py_TYPE(create)->tp_name, "staticmethod") != 0)
+        return std::nullopt;
+    // 3.10: "__wrapped__"
+    Shiboken::AutoDecRef function(PyObject_GetAttrString(create, "__func__"));
+    if (function.isNull()) {
+        PyErr_Format(PyExc_TypeError, "Cannot retrieve function of callback (%S).",
+                     create);
+        return std::nullopt;
     }
+    if (!checkSingletonCallback(function.object()))
+        return std::nullopt;
+    // Reference to the type needs to be kept.
+    return SingletonQObjectCallbackCreation(function.object(),
+                                            reinterpret_cast<PyObject *>(pyObjType));
+}
 
-    PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj);
-    if (typeName == nullptr)
-        typeName = pyObjType->tp_name;
-    if (!PySequence_Contains(pyObjType->tp_mro, reinterpret_cast<PyObject *>(qObjectType()))) {
-        PyErr_Format(PyExc_TypeError, "This decorator can only be used with classes inherited from QObject, got %s.",
-                     typeName);
+PyObject *qmlElementMacro(PyObject *pyObj, const char *decoratorName,
+                          const QByteArray &typeName)
+{
+    auto *pyObjType = checkTypeObject(pyObj, decoratorName);
+    if (pyObjType == nullptr)
         return nullptr;
-    }
-
-    std::string importName = getGlobalString("QML_IMPORT_NAME");
-    int majorVersion = getGlobalInt("QML_IMPORT_MAJOR_VERSION");
-    int minorVersion = getGlobalInt("QML_IMPORT_MINOR_VERSION");
 
-    if (importName.empty()) {
-        PyErr_Format(PyExc_TypeError, "You need specify QML_IMPORT_NAME in order to use %s.",
-                     decoratorName);
+    if (!PySide::isQObjectDerived(pyObjType, false)) {
+        PyErr_Format(PyExc_TypeError,
+                     "%s can only be used with classes inherited from QObject, got %s.",
+                     decoratorName, pyObjType->tp_name);
         return nullptr;
     }
 
-    if (majorVersion == -1) {
-       PyErr_Format(PyExc_TypeError, "You need specify QML_IMPORT_MAJOR_VERSION in order to use %s.",
-                    decoratorName);
-       return nullptr;
-    }
-
-    // Specifying a minor version is optional
-    if (minorVersion == -1)
-        minorVersion = 0;
-
-    const char *uri = importName.c_str();
-    const int result = mode == RegisterMode::Singleton
-        ? PySide::Qml::qmlRegisterSingletonType(pyObj, uri, majorVersion, minorVersion,
-                                                typeName, nullptr,
-                                                PySide::isQObjectDerived(pyObjType, false),
-                                                false)
-        : PySide::Qml::qmlRegisterType(pyObj, uri, majorVersion, minorVersion,
-                                       mode != RegisterMode::Anonymous ? typeName : nullptr,
-                                       noCreationReason,
-                                       mode == RegisterMode::Normal);
-
-    if (result == -1) {
-        PyErr_Format(PyExc_TypeError, "%s: Failed to register type %s.",
-                     decoratorName, typeName);
-    }
-
-    return pyObj;
-}
-
-namespace PySide::Qml {
+    if (!setClassInfo(pyObjType, qmlElementKey, typeName))
+        return nullptr;
 
-PyObject *qmlElementMacro(PyObject *pyObj, const char *decoratorName,
-                          const char *typeName = nullptr)
-{
     RegisterMode mode = RegisterMode::Normal;
-    const char *noCreationReason = nullptr;
     const auto info = PySide::Qml::qmlTypeInfo(pyObj);
     auto *registerObject = pyObj;
     if (info) {
-        if (info->flags.testFlag(PySide::Qml::QmlTypeFlag::Singleton))
+        if (info->flags.testFlag(PySide::Qml::QmlTypeFlag::Singleton)) {
             mode = RegisterMode::Singleton;
-        else if (info->flags.testFlag(PySide::Qml::QmlTypeFlag::Uncreatable))
-            mode = RegisterMode::Uncreatable;
-        noCreationReason = info->noCreationReason.c_str();
+            setSingletonClassInfo(pyObjType);
+        }
         if (info->foreignType)
             registerObject = reinterpret_cast<PyObject *>(info->foreignType);
     }
-    if (!qmlElementMacroHelper(registerObject, decoratorName, typeName, mode, noCreationReason))
+
+    const auto importDataO = getGlobalImportData(decoratorName);
+    if (!importDataO.has_value())
+        return nullptr;
+    const auto importData = importDataO.value();
+
+    int result{};
+    if (mode == RegisterMode::Singleton) {
+        auto singletonCreateMethodO = singletonCreateMethod(pyObjType);
+        if (!singletonCreateMethodO.has_value()) {
+            if (PyErr_Occurred() != nullptr)
+                return nullptr;
+            singletonCreateMethodO = SingletonQObjectFromTypeCreation(pyObj);
+        }
+        result = PySide::Qml::qmlRegisterSingletonTypeV2(registerObject, pyObj, importData,
+                                                         singletonCreateMethodO.value());
+    } else {
+        result = PySide::Qml::qmlRegisterType(registerObject, pyObj, importData);
+    }
+    if (result == -1) {
+        PyErr_Format(PyExc_TypeError, "%s: Failed to register type %s.",
+                     decoratorName, pyObjType->tp_name);
         return nullptr;
+    }
+
     return pyObj;
 }
 
 PyObject *qmlElementMacro(PyObject *pyObj)
 {
-    return qmlElementMacro(pyObj, "QmlElement");
+    return qmlElementMacro(pyObj, "QmlElement", "auto"_ba);
 }
 
-PyObject *qmlNamedElementMacro(PyObject *pyObj, const char *typeName)
+PyObject *qmlNamedElementMacro(PyObject *pyObj, const QByteArray &typeName)
 {
-    return qmlElementMacro(pyObj, "QmlNamedElement", qstrdup(typeName));
+    return qmlElementMacro(pyObj, "QmlNamedElement", typeName);
 }
 
 PyObject *qmlAnonymousMacro(PyObject *pyObj)
 {
-    return qmlElementMacroHelper(pyObj, "QmlAnonymous", nullptr,
-                                 RegisterMode::Anonymous);
+    return qmlElementMacro(pyObj, "QmlAnonymous",  "anonymous"_ba);
 }
 
 PyObject *qmlSingletonMacro(PyObject *pyObj)
index 8d0e8065031ee0fdd89525c4f8a38d1ea5caea90..859172322c618a00d7d1626592fbbe6d2b25691e 100644 (file)
@@ -12,7 +12,7 @@
 QT_BEGIN_NAMESPACE
 namespace QQmlPrivate
 {
-struct RegisterType;
+struct RegisterTypeAndRevisions;
 }
 QT_END_NAMESPACE
 
@@ -22,6 +22,9 @@ namespace PySide::Qml
 /**
  * PySide implementation of qmlRegisterType<T> function.
  *
+ * This is a helper for the legacy free qmlRegisterType*() type functions.
+ * Decorators should be used instead.
+ *
  * \param pyObj Python type to be registered.
  * \param uri QML element uri.
  * \param versionMajor QML component major version.
@@ -37,6 +40,9 @@ PYSIDEQML_API int qmlRegisterType(PyObject *pyObj, const char *uri,
 /**
  * PySide implementation of qmlRegisterSingletonType<T> function.
  *
+ * This is a helper for the legacy free qmlRegisterSingletonType<T> type function.
+ * Decorators should be used instead.
+ *
  * \param pyObj Python type to be registered.
  * \param uri QML element uri.
  * \param versionMajor QML component major version.
@@ -83,7 +89,7 @@ PYSIDEQML_API PyObject *qmlSingletonMacro(PyObject *pyObj);
 // Used by QtQuick module to fill the QQmlPrivate::RegisterType::parserStatusCast,
 // valueSourceCast and valueInterceptorCast fields with the correct values.
 using QuickRegisterItemFunction =
-    bool (*)(PyObject *pyObj, QT_PREPEND_NAMESPACE(QQmlPrivate::RegisterType) *);
+    bool (*)(PyObject *pyObj, QT_PREPEND_NAMESPACE(QQmlPrivate::RegisterTypeAndRevisions) *);
 
 PYSIDEQML_API QuickRegisterItemFunction getQuickRegisterItemFunction();
 PYSIDEQML_API void setQuickRegisterItemFunction(QuickRegisterItemFunction function);
index 3f077ee2a971a17fbaa278bf71d414c3f3ff7d73..f11f92241635d026da49896a7e284a51379c52e5 100644 (file)
@@ -6,12 +6,14 @@
 
 #include <sbkpython.h>
 
+#include <QtCore/QByteArray>
+
 PyTypeObject *qObjectType();
 
 
 namespace PySide::Qml {
 
-PyObject *qmlNamedElementMacro(PyObject *pyObj, const char *typeName);
+PyObject *qmlNamedElementMacro(PyObject *pyObj, const QByteArray &typeName);
 
 }
 
index 0304d33e3e0f0cbf0212b25741c8e4f8aa1c88d4..f369f7400b51ebb02e7c681cee19b3dcf08ec041 100644 (file)
@@ -42,8 +42,6 @@ QDebug operator<<(QDebug d, const QmlTypeInfo &i)
     d.noquote();
     d.nospace();
     d << "QmlTypeInfo(" << i.flags;
-    if (!i.noCreationReason.empty())
-        d << ", noCreationReason=\"" << i.noCreationReason.c_str() << '"';
     if (i.foreignType)
         d << ", foreignType=" << i.foreignType->tp_name;
     if (i.attachedType)
index e10a2b38c3da600ba6ab5996e2af38b073a698fb..112e127a7ba386f9ee0474049426f37bc946b197 100644 (file)
@@ -6,10 +6,10 @@
 
 #include <sbkpython.h>
 
+#include <QtCore/QByteArray>
 #include <QtCore/QFlags>
 
 #include <memory>
-#include <string>
 
 QT_FORWARD_DECLARE_CLASS(QDebug)
 QT_FORWARD_DECLARE_CLASS(QObject)
@@ -19,8 +19,7 @@ namespace PySide::Qml {
 
 enum class QmlTypeFlag
 {
-    Singleton = 0x1,
-    Uncreatable = 0x2
+    Singleton = 0x1
 };
 
 Q_DECLARE_FLAGS(QmlTypeFlags, QmlTypeFlag)
@@ -30,7 +29,6 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QmlTypeFlags)
 struct QmlTypeInfo
 {
     QmlTypeFlags flags;
-    std::string noCreationReason;
     PyTypeObject *foreignType = nullptr;
     PyTypeObject *attachedType = nullptr;
     PyTypeObject *extensionType = nullptr;
index 43c795cb06b022dfe159460c4979224c90dab595..7c0f6b8ff82c223ff7831e4f62b9a0b40e21b821 100644 (file)
@@ -2,17 +2,17 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "pysideqmluncreatable.h"
-#include "pysideqmltypeinfo_p.h"
 #include <pysideclassdecorator_p.h>
+#include <pysideclassinfo.h>
 
 #include <shiboken.h>
 #include <signature.h>
 #include <sbkcppstring.h>
 
-#include <string>
-#include <unordered_map>
+#include <QtCore/qbytearray.h>
+#include <private/qmetaobjectbuilder_p.h>
 
-#include <QtCore/QtGlobal>
+using namespace Qt::StringLiterals;
 
 class PySideQmlUncreatablePrivate : public PySide::ClassDecorator::StringDecoratorPrivate
 {
@@ -35,11 +35,9 @@ PyObject *PySideQmlUncreatablePrivate::tp_call(PyObject *self, PyObject *args, P
     if (klass== nullptr)
         return nullptr;
 
+    auto *type = reinterpret_cast<PyTypeObject *>(klass);
     auto *data = DecoratorPrivate::get<PySideQmlUncreatablePrivate>(self);
-
-    const auto info = PySide::Qml::ensureQmlTypeInfo(klass);
-    info->flags.setFlag(PySide::Qml::QmlTypeFlag::Uncreatable);
-    info->noCreationReason = data->string();
+    setUncreatableClassInfo(type, data->string());
 
     Py_INCREF(klass);
     return klass;
@@ -105,3 +103,16 @@ void initQmlUncreatable(PyObject *module)
     PyModule_AddObject(module, "QmlUncreatable",
                        reinterpret_cast<PyObject *>(PySideQmlUncreatable_TypeF()));
 }
+
+void setUncreatableClassInfo(PyTypeObject *type, const QByteArray &reason)
+{
+    PySide::ClassInfo::setClassInfo(type, {
+        {"QML.Creatable"_ba, "false"_ba},
+        {"QML.UncreatableReason"_ba, reason} });
+}
+
+void setUncreatableClassInfo(QMetaObjectBuilder *builder, const QByteArray &reason)
+{
+    builder->addClassInfo("QML.Creatable", "false");
+    builder->addClassInfo("QML.UncreatableReason", reason);
+}
index 7961634cade1b972ee004d11da2d0a50d888d981..8a8adb3c834cce94b6bfc3fb1689e90f3f586818 100644 (file)
@@ -6,6 +6,10 @@
 
 #include <sbkpython.h>
 
+#include <QtCore/QByteArray>
+
+QT_FORWARD_DECLARE_CLASS(QMetaObjectBuilder)
+
 // The QmlUncreatable decorator modifies QmlElement to register an uncreatable
 // type. Due to the (reverse) execution order of decorators, it needs to follow
 // QmlElement.
@@ -16,4 +20,7 @@ extern "C"
 
 void initQmlUncreatable(PyObject *module);
 
+void setUncreatableClassInfo(PyTypeObject *type, const QByteArray &reason);
+void setUncreatableClassInfo(QMetaObjectBuilder *builder, const QByteArray &reason);
+
 #endif // PYSIDEQMLUNCREATABLE_H
index c86d328cfc6cd44053c43ac74e29fa0653d61b2c..7176523141aea33bba069f3654d522ed2f953e4e 100644 (file)
@@ -19,6 +19,9 @@ target_sources(PySidePlugin PRIVATE
 )
 
 # See libshiboken/CMakeLists.txt
+
+target_compile_definitions(PySidePlugin PRIVATE -DQT_NO_KEYWORDS=1)
+
 if(PYTHON_LIMITED_API)
     target_compile_definitions(PySidePlugin PRIVATE "-DPy_LIMITED_API=0x03050000")
 endif()
index ccff635a91527e6c8c0b1d08fcd27cbf3f7be607..d23156a9d782a0e55bbf4e40f98d5188d9b6f727 100644 (file)
@@ -55,7 +55,7 @@ static QString pyStr(PyObject *o)
 
 static QString pyErrorMessage()
 {
-    QString result = QLatin1String("<error information not available>");
+    QString result = "<error information not available>"_L1;
     PyObject *ptype = {};
     PyObject *pvalue = {};
     PyObject *ptraceback = {};
@@ -87,7 +87,7 @@ static bool runPyScript(const char *script, QString *errorMessage)
 {
     PyObject *main = PyImport_AddModule("__main__");
     if (main == nullptr) {
-        *errorMessage = QLatin1String("Internal error: Cannot retrieve __main__");
+        *errorMessage = "Internal error: Cannot retrieve __main__"_L1;
         return false;
     }
     PyObject *globalDictionary = PyModule_GetDict(main);
@@ -118,8 +118,7 @@ static bool runPyScriptFile(const QString &fileName, QString *errorMessage)
     file.close();
     const bool ok = runPyScript(script.constData(), errorMessage);
     if (!ok && !errorMessage->isEmpty()) {
-        errorMessage->prepend(QLatin1String("Error running ") + fileName
-                              + QLatin1String(": "));
+        errorMessage->prepend("Error running "_L1 + fileName + ": "_L1);
     }
     return ok;
 }
index bfc17ffbae15d227c658f5cb868a4a0e6792c2d1..52621f0bd2f0a6983e4c7b43740f2a7fe4976aa7 100644 (file)
@@ -8,8 +8,6 @@
 
 #include <QtUiPlugin/QDesignerCustomWidgetInterface>
 
-#include <QtCore/qglobal.h>
-
 class PyCustomWidget: public QObject, public QDesignerCustomWidgetInterface
 {
      Q_OBJECT
index c581a8d0f9702d742a18f3f615bb9888195601ca..539e1aea8081ec274712b0619f05ffaa8cf35e87 100644 (file)
@@ -17,7 +17,7 @@ endif()
 # the path to the testbinding module
 get_filename_component(BUILD_DIR "${CMAKE_BINARY_DIR}" DIRECTORY)
 get_filename_component(BUILD_DIR "${CMAKE_BINARY_DIR}" DIRECTORY)
-set(QT_DIR "${_qt5Core_install_prefix}")
+set(QT_DIR "${QT6_INSTALL_PREFIX}")
 
 macro(TEST_QT_MODULE var name)
   if(NOT DISABLE_${name} AND ${var})
diff --git a/sources/pyside6/tests/QtAsyncio/qasyncio_test_cancel_taskgroup.py b/sources/pyside6/tests/QtAsyncio/qasyncio_test_cancel_taskgroup.py
new file mode 100644 (file)
index 0000000..aa8ce47
--- /dev/null
@@ -0,0 +1,57 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for QtAsyncio'''
+
+import asyncio
+import unittest
+
+import PySide6.QtAsyncio as QtAsyncio
+
+
+class QAsyncioTestCaseCancelTaskGroup(unittest.TestCase):
+    def setUp(self) -> None:
+        super().setUp()
+        # We only reach the end of the loop if the task is not cancelled.
+        self.loop_end_reached = False
+
+    async def raise_error(self):
+        raise RuntimeError
+
+    async def loop_short(self):
+        self._loop_end_reached = False
+        for _ in range(1000):
+            await asyncio.sleep(1e-3)
+        self._loop_end_reached = True
+
+    async def loop_shorter(self):
+        self._loop_end_reached = False
+        for _ in range(1000):
+            await asyncio.sleep(1e-4)
+        self._loop_end_reached = True
+
+    async def loop_the_shortest(self):
+        self._loop_end_reached = False
+        for _ in range(1000):
+            await asyncio.to_thread(lambda: None)
+        self._loop_end_reached = True
+
+    async def main(self, coro):
+        async with asyncio.TaskGroup() as tg:
+            tg.create_task(coro())
+            tg.create_task(self.raise_error())
+
+    def test_cancel_taskgroup(self):
+        coros = [self.loop_short, self.loop_shorter, self.loop_the_shortest]
+
+        for coro in coros:
+            try:
+                QtAsyncio.run(self.main(coro), keep_running=False)
+            except ExceptionGroup as e:
+                self.assertEqual(len(e.exceptions), 1)
+                self.assertIsInstance(e.exceptions[0], RuntimeError)
+                self.assertFalse(self._loop_end_reached)
+
+
+if __name__ == '__main__':
+    unittest.main()
index f584bfde6dae939288e37a99d4ba3baa950e31d3..f0228d943e70937ea572902b42ad0448acd285d4 100644 (file)
@@ -34,6 +34,7 @@ PYSIDE_TEST(bug_1313.py)
 PYSIDE_TEST(bug_PYSIDE-41.py)
 PYSIDE_TEST(bug_PYSIDE-42.py)
 PYSIDE_TEST(bug_PYSIDE-164.py)
+PYSIDE_TEST(bug_PYSIDE-2745.py)
 PYSIDE_TEST(blocking_signals_test.py)
 PYSIDE_TEST(classinfo_test.py)
 PYSIDE_TEST(child_event_test.py)
index d8159c2efd1fe4002c899dbf5ba045ffddc9413b..493abb071d5c7f7258a7532e5fe5d3c31e894797 100644 (file)
@@ -14,7 +14,12 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, QFile, QSignalBlocker
+from PySide6.QtCore import QObject, Signal, QFile, QSignalBlocker
+
+
+class Sender(QObject):
+    mysignal = Signal()
+    mysignal_int_int = Signal(int, int)
 
 
 class TestSignalsBlockedBasic(unittest.TestCase):
@@ -61,7 +66,7 @@ class TestSignalsBlocked(unittest.TestCase):
 
     def setUp(self):
         # Set up the basic resources needed
-        self.obj = QObject()
+        self.obj = Sender()
         self.args = tuple()
         self.called = False
 
@@ -81,27 +86,28 @@ class TestSignalsBlocked(unittest.TestCase):
 
     def testShortCircuitSignals(self):
         # Blocking of Python short-circuit signals
-        QObject.connect(self.obj, SIGNAL('mysignal()'), self.callback)
+        self.obj.mysignal.connect(self.callback)
 
-        self.obj.emit(SIGNAL('mysignal()'))
+        self.obj.mysignal.emit()
         self.assertTrue(self.called)
 
         self.called = False
         self.obj.blockSignals(True)
-        self.obj.emit(SIGNAL('mysignal()'))
+        self.obj.mysignal.emit()
         self.assertTrue(not self.called)
 
     def testPythonSignals(self):
         # Blocking of Python typed signals
-        QObject.connect(self.obj, SIGNAL('mysignal(int,int)'), self.callback)
+
+        self.obj.mysignal_int_int.connect(self.callback)
         self.args = (1, 3)
 
-        self.obj.emit(SIGNAL('mysignal(int,int)'), *self.args)
+        self.obj.mysignal_int_int.emit(*self.args)
         self.assertTrue(self.called)
 
         self.called = False
         self.obj.blockSignals(True)
-        self.obj.emit(SIGNAL('mysignal(int,int)'), *self.args)
+        self.obj.mysignal_int_int.emit(*self.args)
         self.assertTrue(not self.called)
 
 
@@ -130,7 +136,7 @@ class TestQFileSignalBlocking(unittest.TestCase):
     def testAboutToCloseBlocking(self):
         # QIODevice.aboutToClose() blocking
 
-        QObject.connect(self.qfile, SIGNAL('aboutToClose()'), self.callback)
+        self.qfile.aboutToClose.connect(self.callback)
 
         self.assertTrue(self.qfile.open(QFile.ReadOnly))
         self.qfile.close()
index 1ecea61b24b769ed235c88800ec032aba3082deb..c15a7014b4b48c6c53082c89cddc459247015b87 100644 (file)
@@ -24,7 +24,7 @@ class thread_function():
 
 class Task(QRunnable):
     def run(self):
-        QThread.sleep(2)  # Sleep 2 seconds
+        QThread.msleep(100)
 
 
 class QThreadPoolTest(unittest.TestCase):
@@ -34,15 +34,15 @@ class QThreadPoolTest(unittest.TestCase):
         for i in range(3):
             task = Task()
             QThreadPool.globalInstance().start(task)
-            time.sleep(1)  # Sleep 1 second
+            time.sleep(0.05)
 
-        QThreadPool.globalInstance().waitForDone()
+        self.assertTrue(QThreadPool.globalInstance().waitForDone())
 
     def testCallable(self):
         global thread_function_called
         tp = QThreadPool.globalInstance()
         tp.start(thread_function)
-        tp.waitForDone()
+        self.assertTrue(tp.waitForDone())
         self.assertTrue(thread_function_called)
 
 
index bc92e5736e7a47d2b7021f983cb6ed35ff791a0a..a8c9799e0407df80fa283a0454f30b67fd5d9dd7 100644 (file)
@@ -19,7 +19,7 @@ class TestBug987(unittest.TestCase):
 
     def testInvalidDisconnection(self):
         o = QObject()
-        self.assertRaises(RuntimeError, o.destroyed.disconnect, self.callback)
+        self.assertFalse(o.destroyed.disconnect(self.callback))
 
 
 if __name__ == '__main__':
index c5a6736a878f6e8e778d3c94bcfcc5057dc7c4f6..84859af84469bdcefde66982df157ad100979721 100644 (file)
@@ -10,16 +10,19 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QCoreApplication, QEventLoop, QObject, Qt, QThread, QTimer, SIGNAL
+from PySide6.QtCore import QCoreApplication, QEventLoop, QObject, Qt, QThread, Signal
 
 
 class Emitter(QThread):
+
+    signal = Signal(int)
+
     def __init__(self):
         super().__init__()
 
     def run(self):
         print("Before emit.")
-        self.emit(SIGNAL("signal(int)"), 0)
+        self.signal.emit(0)
         print("After emit.")
 
 
@@ -36,12 +39,11 @@ class Receiver(QObject):
 class TestBugPYSIDE164(unittest.TestCase):
 
     def testBlockingSignal(self):
-        app = QCoreApplication.instance() or QCoreApplication([])
+        app = QCoreApplication.instance() or QCoreApplication([])  # noqa: F841
         eventloop = QEventLoop()
         emitter = Emitter()
         receiver = Receiver(eventloop)
-        emitter.connect(emitter, SIGNAL("signal(int)"),
-                        receiver.receive, Qt.BlockingQueuedConnection)
+        emitter.signal.connect(receiver.receive, Qt.BlockingQueuedConnection)
         emitter.start()
         retval = eventloop.exec()
         emitter.wait(2000)
diff --git a/sources/pyside6/tests/QtCore/bug_PYSIDE-2745.py b/sources/pyside6/tests/QtCore/bug_PYSIDE-2745.py
new file mode 100644 (file)
index 0000000..3d6c603
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from PySide6.QtCore import QTimer
+
+from helper.usesqapplication import UsesQApplication
+
+
+class TestBugPYSIDE2745(UsesQApplication):
+
+    def setUp(self):
+        UsesQApplication.setUp(self)
+        self.counter = 0
+
+    def fail(self):
+        self.counter += 1
+        raise Exception()
+
+    def test_fail(self):
+        QTimer.singleShot(0, self.fail)
+        QTimer.singleShot(0, self.fail)
+        QTimer.singleShot(1, self.app.quit)
+        self.app.exec()
+        self.assertEqual(self.counter, 2)
+
+
+if __name__ == '__main__':
+    unittest.main()
index 8cb38882afd177b217517deb66cc9dd0c10c0e47..97c4f942e89cae81d341310085e3bdcbcb197348 100644 (file)
@@ -34,7 +34,6 @@ This test is in its own file because combining it with
 @unittest.skipIf(is_pypy, "__feature__ cannot yet be used with PyPy")
 class ErrormessagesWithFeatures(unittest.TestCase):
     probe = "called with wrong argument types"
-    probe_miss = "missing signature"
 
     def setUp(self):
         qApp or QApplication()
@@ -76,20 +75,20 @@ class ErrormessagesWithFeatures(unittest.TestCase):
         with self.assertRaises(TypeError) as cm:
             QApplication.quitOnLastWindowClosed = object
         print("\n\n" + cm.exception.args[0])
-        self.assertTrue(self.probe_miss in cm.exception.args[0])
+        self.assertTrue(self.probe in cm.exception.args[0])
         with self.assertRaises(TypeError) as cm:
             qApp.quitOnLastWindowClosed = object
-        self.assertTrue(self.probe_miss in cm.exception.args[0])
+        self.assertTrue(self.probe in cm.exception.args[0])
 
     def testCorrectErrorMessagesClassSnakeProp(self):
         from __feature__ import snake_case, true_property
         with self.assertRaises(TypeError) as cm:
             QApplication.quit_on_last_window_closed = object
         print("\n\n" + cm.exception.args[0])
-        self.assertTrue(self.probe_miss in cm.exception.args[0])
+        self.assertTrue(self.probe in cm.exception.args[0])
         with self.assertRaises(TypeError) as cm:
             qApp.quit_on_last_window_closed = object
-        self.assertTrue(self.probe_miss in cm.exception.args[0])
+        self.assertTrue(self.probe in cm.exception.args[0])
 
     def testDocIsWorking(self):
         """
index acd1007862eea982d320c4206de9960a9a6df0bf..aee2f516c0e44e46efd8e0bd41c17118bceb1fbc 100644 (file)
@@ -15,13 +15,17 @@ from PySide6.QtCore import QDate, QDateTime, QTime, QUrl
 from PySide6.QtCore import QLine, QPoint, QRect, QSize
 
 
+URL = "https://qt.io/"
+
+
 class HashTest(unittest.TestCase):
     def testInsert(self):
         myHash = {}
         qdate = QDate.currentDate()
         qdatetime = QDateTime.currentDateTime()
         qtime = QTime.currentTime()
-        qurl = QUrl("http://www.pyside.org")
+        qurl = QUrl(URL)
+        self.assertTrue(qurl.isValid())
         qpoint = QPoint(12, 42)
 
         myHash[qdate] = "QDate"
@@ -64,7 +68,34 @@ class HashTest(unittest.TestCase):
         self.assertEqual(l1, l2)
         self.assertEqual(hash(l1), hash(l2))
 
+    def testQTimeHash(self):
+        t1 = QTime(5, 5, 5)
+        t2 = QTime(5, 5, 5)
+        self.assertFalse(t1 is t2)
+        self.assertEqual(t1, t2)
+        self.assertEqual(hash(t1), hash(t2))
+
+    def testQDateHash(self):
+        d1 = QDate(1968, 3, 9)
+        d2 = QDate(1968, 3, 9)
+        self.assertFalse(d1 is d2)
+        self.assertEqual(d1, d2)
+        self.assertEqual(hash(d1), hash(d2))
+
+    def testQDateTimeHash(self):
+        d1 = QDateTime(QDate(1968, 3, 9), QTime(5, 5, 5))
+        d2 = QDateTime(QDate(1968, 3, 9), QTime(5, 5, 5))
+        self.assertFalse(d1 is d2)
+        self.assertEqual(d1, d2)
+        self.assertEqual(hash(d1), hash(d2))
+
+    def testQUrlHash(self):
+        u1 = QUrl(URL)
+        u2 = QUrl(URL)
+        self.assertFalse(u1 is u2)
+        self.assertEqual(u1, u2)
+        self.assertEqual(hash(u1), hash(u2))
+
 
 if __name__ == '__main__':
     unittest.main()
-
index c00674859e4ed74482997bb6b3d68a8043650811..cb8f9a43102f53e61cf6241ec8467c7857e3a99d 100644 (file)
@@ -6,6 +6,7 @@
 import ctypes
 import os
 import pickle
+import struct
 import sys
 import unittest
 
@@ -15,7 +16,8 @@ from init_paths import init_test_paths
 init_test_paths(False)
 
 
-from PySide6.QtCore import QByteArray, QSettings, QObject, QDataStream, QIODevice
+from PySide6.QtCore import (QByteArray, QSettings, QObject, QDataStream,
+                            QIODevice, qCompress, qUncompress)
 
 
 class QByteArrayTestToNumber(unittest.TestCase):
@@ -255,6 +257,34 @@ class QByteArraySliceAssignment(unittest.TestCase):
         actual_bytes = bytes(byte_array)
         self.assertEqual(orig_bytes, actual_bytes)
 
+    def testUnpack(self):
+        b = QByteArray(b'\x19\x00\x00\x00\xc4\t\x00\x00')
+        t = struct.unpack('<ii', b)
+        self.assertEqual(len(t), 2)
+        self.assertEqual(t[0], 25)
+        self.assertEqual(t[1], 2500)
+
+
+class QCompressTest(unittest.TestCase):
+    def testQByteArrayCompression(self):
+        """Compress/uncompress a QByteArray."""
+        data = bytes(10 * 'long redundant sentence bla bla', "UTF8")
+        ba = QByteArray(data)
+        compressed = qCompress(ba)
+        self.assertTrue(len(compressed) < len(data))
+        uncompressed = qUncompress(compressed)
+        self.assertEqual(uncompressed, data)
+
+    def testBufferCompression(self):
+        """Compress/uncompress portions of bytes without converting to
+           QByteArray."""
+        data = bytes(10 * 'long redundant sentence bla bla', "UTF8")
+        used_len = int(len(data) / 2)
+        compressed = qCompress(data, used_len, -1)
+        self.assertTrue(len(compressed) < used_len)
+        uncompressed = qUncompress(compressed.data(), len(compressed))
+        self.assertEqual(uncompressed, data[:used_len])
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/sources/pyside6/tests/QtCore/qiopipe_test.py b/sources/pyside6/tests/QtCore/qiopipe_test.py
new file mode 100644 (file)
index 0000000..53a6ba7
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+'''Test cases for the QIOPipe class'''
+
+from PySide6.QtCore import QIODevice, QIOPipe
+
+import unittest
+
+
+class QIOPipeTest(unittest.TestCase):
+    def setUp(self) -> None:
+        self.pipe = QIOPipe()
+        self.pipe.open(QIODevice.OpenModeFlag.ReadWrite)
+        return super().setUp()
+
+    def tearDown(self) -> None:
+        super().tearDown()
+
+    def ready_read_bytes_written(self):
+        received_data = self.pipe.end2().readAll().data()
+        self.assertEqual(received_data, self.data)
+
+    def test_readyRead(self):
+        self.data = b"Hello, World!"
+        self.pipe.end2().readyRead.connect(self.ready_read_bytes_written)
+        self.pipe.end1().write(self.data)
+
+    def test_bytesWritten(self):
+        self.data = b"Hello, World!"
+        self.pipe.end2().bytesWritten.connect(self.ready_read_bytes_written)
+        self.pipe.end1().write(self.data)
+
+
+if __name__ == '__main__':
+    unittest.main()
index 106bca02a2aaebd589e192464492e456069b1856..6dca9235cc1b6963ec4980375b9034fcb361c03c 100644 (file)
@@ -32,6 +32,9 @@ class TestQMessageAuthenticationCode (unittest.TestCase):
         lockFile = QLockFile(self._fileName)
         self.assertTrue(lockFile.lock())
         self.assertTrue(lockFile.isLocked())
+        lock_info = lockFile.getLockInfo();
+        self.assertEqual(len(lock_info), 3)
+        self.assertEqual(lock_info[0], os.getpid())
         lockFile.unlock()
 
 
index 8f6467a07721f0eb7daf06dc2824543cb929dc17..4b3051711a4974a8e5d9df1b0bb7e634cb0cb3bd 100644 (file)
@@ -105,15 +105,6 @@ class qmetaobject_test(unittest.TestCase):
 
         o.connect(o2, SIGNAL("bars()"), o.slot)
         self.assertTrue(o2.metaObject().indexOfMethod("bars()") > -1)
-        #self.assertTrue(o.metaObject().indexOfMethod("bar()") == -1)
-        #self.assertTrue(o.metaObject().indexOfMethod("slot()") > -1)
-
-        #slot_index = o.metaObject().indexOfMethod("slot()")
-
-        #o.connect(o, SIGNAL("foo()"), o2, SIGNAL("bar()"))
-        #signal_index = o.metaObject().indexOfMethod("foo()");
-
-        #self.assertTrue(slot_index != signal_index)
 
     # PYSIDE-784, plain Qt objects should not have intermediary
     # metaObjects.
@@ -125,7 +116,7 @@ class qmetaobject_test(unittest.TestCase):
     # PYSIDE-1827, slots with non-QObject object types should work
     # (metatypes are registered)
     def test_ObjectSlotSignal(self):
-        app = QCoreApplication()
+        app = QCoreApplication()  # noqa: F841
         sender = SemaphoreSender()
         receiver = SemaphoreReceiver()
         sender.signal.connect(receiver.receiverSlot, Qt.QueuedConnection)
index 90c99edb4b67ba3345dca64a16544641dac243e5..6a63edb859b88b151c2b88f4a864b18a289b2953 100644 (file)
@@ -4,7 +4,6 @@
 
 '''Unit tests for QMimeDatabase'''
 
-import ctypes
 import os
 import sys
 import unittest
@@ -24,8 +23,7 @@ class QMimeDatabaseTest(unittest.TestCase):
         s0 = db.mimeTypeForName("application/x-zerosize")
         self.assertTrue(s0.isValid())
         self.assertEqual(s0.name(), "application/x-zerosize")
-        if "en" in QLocale().name():
-            self.assertEqual(s0.comment(), "empty document")
+        self.assertTrue(s0.comment())
 
         s0Again = db.mimeTypeForName("application/x-zerosize")
         self.assertEqual(s0Again.name(), s0.name())
@@ -40,13 +38,13 @@ class QMimeDatabaseTest(unittest.TestCase):
         rdf = db.mimeTypeForName("application/rdf+xml")
         self.assertTrue(rdf.isValid())
         self.assertEqual(rdf.name(), "application/rdf+xml")
+        self.assertTrue(rdf.comment())
         if "en" in QLocale().name():
             self.assertEqual(rdf.comment(), "RDF file")
 
         bzip2 = db.mimeTypeForName("application/x-bzip2")
         self.assertTrue(bzip2.isValid())
-        if "en" in QLocale().name():
-            self.assertEqual(bzip2.comment(), "Bzip archive")
+        self.assertTrue(bzip2.comment())
 
         defaultMime = db.mimeTypeForName("application/octet-stream")
         self.assertTrue(defaultMime.isValid())
index b93408d1096671eddf36f3b19ff926798a3492c9..b3bfaf007fedbbb2cceb9959bd19c756755d26d6 100644 (file)
@@ -12,7 +12,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, SLOT
+from PySide6.QtCore import QObject, Signal, SIGNAL, SLOT
 from helper.usesqapplication import UsesQApplication
 
 
@@ -21,6 +21,9 @@ def cute_slot():
 
 
 class Obj(QObject):
+
+    foo = Signal()
+
     def __init__(self):
         super().__init__()
         self.con_notified = False
@@ -49,6 +52,15 @@ class TestQObjectConnectNotify(UsesQApplication):
         UsesQApplication.tearDown(self)
 
     def testBasic(self):
+        sender = Obj()
+        receiver = QObject()
+        sender.destroyed.connect(receiver.deleteLater)
+        self.assertTrue(sender.con_notified)
+        self.assertEqual(sender.signal.methodSignature(), "destroyed()")
+        self.assertTrue(sender.destroyed.disconnect(receiver.deleteLater))
+        self.assertTrue(sender.dis_notified)
+
+    def testBasicString(self):
         sender = Obj()
         receiver = QObject()
         sender.connect(SIGNAL("destroyed()"), receiver, SLOT("deleteLater()"))
@@ -57,31 +69,29 @@ class TestQObjectConnectNotify(UsesQApplication):
         # will use the non-cloned method signature, so connecting to destroyed() will actually
         # connect to destroyed(QObject*).
         self.assertEqual(sender.signal.methodSignature(), "destroyed(QObject*)")
-        sender.disconnect(SIGNAL("destroyed()"), receiver, SLOT("deleteLater()"))
+        self.assertTrue(sender.disconnect(SIGNAL("destroyed()"), receiver, SLOT("deleteLater()")))
         self.assertTrue(sender.dis_notified)
 
     def testPySignal(self):
         sender = Obj()
         receiver = QObject()
-        sender.connect(SIGNAL("foo()"), receiver, SLOT("deleteLater()"))
+        sender.foo.connect(receiver.deleteLater)
         self.assertTrue(sender.con_notified)
-        sender.disconnect(SIGNAL("foo()"), receiver, SLOT("deleteLater()"))
+        self.assertTrue(sender.foo.disconnect(receiver.deleteLater))
         self.assertTrue(sender.dis_notified)
 
     def testPySlots(self):
         sender = Obj()
-        receiver = QObject()
-        sender.connect(SIGNAL("destroyed()"), cute_slot)
+        sender.destroyed.connect(cute_slot)
         self.assertTrue(sender.con_notified)
-        sender.disconnect(SIGNAL("destroyed()"), cute_slot)
+        self.assertTrue(sender.destroyed.disconnect(cute_slot))
         self.assertTrue(sender.dis_notified)
 
     def testpyAll(self):
         sender = Obj()
-        receiver = QObject()
-        sender.connect(SIGNAL("foo()"), cute_slot)
+        sender.foo.connect(cute_slot)
         self.assertTrue(sender.con_notified)
-        sender.disconnect(SIGNAL("foo()"), cute_slot)
+        self.assertTrue(sender.foo.disconnect(cute_slot))
         self.assertTrue(sender.dis_notified)
 
 
index 1cf07fbab5defd71bdd7e906be55ed89c1657f33..ab7a1b6ad20698d62dbd3cedd59f0a4b66d9f07e 100644 (file)
@@ -63,6 +63,17 @@ class FilteredObject(QObject):
             self.app.quit()
 
 
+class PolymorphicIdFilterObject(QObject):
+    """PYSIDE-2675: Check whether QChildEvent.added() is accessible via PolymorphicId"""
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.added = False
+
+    def event(self, event):
+        self.added = event.added()
+        return False
+
+
 class TestQObjectEventFilterPython(UsesQApplication):
     '''QObject.eventFilter - Reimplemented in python
     Filters 5 TimerEvents and then bypasses the other events to the
@@ -93,6 +104,11 @@ class TestQObjectEventFilterPython(UsesQApplication):
         self.assertEqual(filtered.times_called, 5)
         self.assertEqual(self.obj_filter.events_handled, 5)
 
+    def testPolymorphicId(self):
+        testObject = PolymorphicIdFilterObject()
+        t2 = QObject(testObject)  # noqa: F841
+        self.assertTrue(testObject.added)
+
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testInstallEventFilterRefCountAfterDelete(self):
         '''Bug 910 - installEventFilter() increments reference count on target object
index 061ce916062a170da831b34b9d2fd823445c3052..a95afb090f31bdf8e3294dc884ae93a58c691af2 100644 (file)
@@ -11,7 +11,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QCoreApplication, QObject, QTimer, SIGNAL, SLOT
+from PySide6.QtCore import QCoreApplication, QObject, QTimer
 
 """
 This is a simple slot test that was updated to use the qApp "macro".
@@ -28,24 +28,23 @@ class objTest(QObject):
 
     def slot(self):
         self.ok = True
-        qApp.quit()
+        qApp.quit()  # noqa: F821
 
 
 class slotTest(unittest.TestCase):
     def quit_app(self):
-        qApp.quit()
+        qApp.quit()  # noqa: F821
 
     def testBasic(self):
         timer = QTimer()
         timer.setInterval(100)
 
         my_obj = objTest()
-        my_slot = SLOT("slot()")
-        QObject.connect(timer, SIGNAL("timeout()"), my_obj, my_slot)
+        timer.timeout.connect(my_obj.slot)
         timer.start(100)
 
         QTimer.singleShot(1000, self.quit_app)
-        qApp.exec()
+        qApp.exec()  # noqa: F821
 
         self.assertTrue(my_obj.ok)
 
index 9718a242745ea67de0d44fc7e93d476f47373aa3..2ccaa300eb06d0409ee9e7077c8997bfc1964bbc 100644 (file)
@@ -14,7 +14,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, QThread, QTimer, Signal
+from PySide6.QtCore import QObject, QThread, QTimer, Signal, Slot, SLOT
 from helper.usesqapplication import UsesQApplication
 
 
@@ -74,6 +74,11 @@ class TestSingleShot(UsesQApplication):
         self.app.exec()
         self.assertTrue(self.called)
 
+    def testSingleShotZero(self):
+        QTimer.singleShot(0, self.callback)
+        self.app.exec()
+        self.assertTrue(self.called)
+
     def testSingleShotWithContext(self):
         thread = ThreadForContext()
         thread.start()
@@ -97,6 +102,56 @@ class TestSingleShot(UsesQApplication):
         self.assertEqual(self.qthread, thread.qthread)
 
 
+class TestSingleShotCallableObject(UsesQApplication):
+    '''Test case for QTimer.singleShot with callable inside an object'''
+
+    def setUp(self):
+        # Acquire resources
+        UsesQApplication.setUp(self)
+        self.watchdog = WatchDog(self)
+
+    def tearDown(self):
+        # Release resources
+        del self.watchdog
+        # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+        gc.collect()
+        UsesQApplication.tearDown(self)
+
+    class CallbackObject(QObject):
+        def __init__(self, app) -> None:
+            super().__init__()
+            self.app = app
+
+        @Slot()
+        def func(self):
+            self.called = True
+            self.app.quit()
+
+    def testSingleShotWithObjectAndMember(self):
+        callback = self.CallbackObject(self.app)
+        QTimer.singleShot(100, callback, SLOT("func()"))
+        self.app.exec()
+        self.assertTrue(callback.called)
+
+    def testSingleShotWithObjectAndMemberZero(self):
+        callback = self.CallbackObject(self.app)
+        QTimer.singleShot(0, callback, SLOT("func()"))
+        self.app.exec()
+        self.assertTrue(callback.called)
+
+    def testSingleShotWithCallableInObject(self):
+        callback = self.CallbackObject(self.app)
+        QTimer.singleShot(100, callback.func)
+        self.app.exec()
+        self.assertTrue(callback.called)
+
+    def testSingleShotWithCallableInObjectZero(self):
+        callback = self.CallbackObject(self.app)
+        QTimer.singleShot(0, callback.func)
+        self.app.exec()
+        self.assertTrue(callback.called)
+
+
 class SigEmitter(QObject):
 
     sig1 = Signal()
@@ -128,6 +183,13 @@ class TestSingleShotSignal(UsesQApplication):
         self.app.exec()
         self.assertTrue(self.called)
 
+    def testSingleShotSignalZero(self):
+        emitter = SigEmitter()
+        emitter.sig1.connect(self.callback)
+        QTimer.singleShot(0, emitter.sig1)
+        self.app.exec()
+        self.assertTrue(self.called)
+
 
 if __name__ == '__main__':
     unittest.main()
index b0a5f018647299b00475f44f84283493809445b7..a453d1ac150a73b3f3bac8e03673ef08c28d2086 100644 (file)
@@ -12,14 +12,16 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, QFile, QThread, QTimer, Qt
+from PySide6.QtCore import Signal, QThread
 from helper.usesqapplication import UsesQApplication
 
 
 class MyThread(QThread):
 
+    test = Signal(str)
+
     def run(self):
-        self.emit(SIGNAL("test(const QString&)"), "INdT - PySide")
+        self.test.emit("INdT - PySide")
 
 
 class TestThreadSignal(UsesQApplication):
@@ -33,7 +35,7 @@ class TestThreadSignal(UsesQApplication):
 
     def testThread(self):
         t = MyThread()
-        QObject.connect(t, SIGNAL("test(const QString&)"), self._callback)
+        t.test.connect(self._callback)
         t.start()
 
         self.app.exec()
index 053f073317ebf9c54ff152341b3776fddccf33f1..dc51a74e6a8403693c88d62ede7bebf420fd8167 100644 (file)
@@ -11,7 +11,7 @@ from init_paths import init_test_paths
 init_test_paths(False)
 
 from PySide6.QtCore import QPointF
-from PySide6.QtGui import QTransform, QPolygonF, QPolygonF
+from PySide6.QtGui import QTransform, QPolygonF, QPolygonF, QQuaternion, QVector3D
 
 
 class QTransformTest(unittest.TestCase):
@@ -78,6 +78,12 @@ class QTransformTest(unittest.TestCase):
 
         self.assertEqual(t1, r2)
 
+    def testQQuaternion(self):
+        """Test return tuples."""
+        q = QQuaternion(1, 1, 1, 1)
+        self.assertEqual(len(q.getAxisAndAngle()), 2)
+        self.assertEqual(len(q.getEulerAngles()), 3)
+
 
 if __name__ == "__main__":
     unittest.main()
index c45d762b5c2d62d5830815470e504cc73aa019ad..6e9a661cee0284337c91cdf391f6b6122641ab2c 100644 (file)
@@ -7,13 +7,10 @@ import unittest
 
 from pathlib import Path
 sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
-from init_paths import init_test_paths
+from init_paths import init_test_paths  # noqa: E402
 init_test_paths(False)
 
 from helper.timedqguiapplication import TimedQGuiApplication
-from PySide6.support import deprecated
-from PySide6.support.signature import importhandler
-from PySide6 import QtGui
 
 
 class TestTimedApp(TimedQGuiApplication):
@@ -23,21 +20,7 @@ class TestTimedApp(TimedQGuiApplication):
         # Simple test of TimedQGuiApplication
         self.app.exec()
 
-
-def fix_for_QtGui(QtGui):
-    QtGui.something = 42
-
-
-class TestPatchingFramework(unittest.TestCase):
-    """Simple test that verifies that deprecated.py works"""
-
-    deprecated.fix_for_QtGui = fix_for_QtGui
-
-    def test_patch_works(self):
-        something = "something"
-        self.assertFalse(hasattr(QtGui, something))
-        importhandler.finish_import(QtGui)
-        self.assertTrue(hasattr(QtGui, something))
+# deprecated.py is no longer needed.
 
 
 if __name__ == '__main__':
index 720f0ef99270bda2aea05ff0ae82d4bf2f1fd193..30bf7e78684027013ba7e11a83f7f4138d73caa7 100644 (file)
@@ -17,6 +17,7 @@ PYSIDE_TEST(bug_997.py)
 PYSIDE_TEST(bug_1029.py)
 PYSIDE_TEST(groupedproperty.py)
 PYSIDE_TEST(listproperty.py)
+PYSIDE_TEST(qmlregistertype_test.py)
 PYSIDE_TEST(qqmlapplicationengine_test.py)
 PYSIDE_TEST(qqmlnetwork_test.py)
 PYSIDE_TEST(qqmlcomponent_test.py)
index 8916aefe572bcb238b40c30869354c97061594af..884600d29ad350527e10e5bff42f6c1671189c35 100644 (file)
@@ -7,11 +7,25 @@ import unittest
 
 from pathlib import Path
 sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
-from init_paths import init_test_paths
+from init_paths import init_test_paths  # noqa: E402
 init_test_paths(False)
 
-from PySide6.QtCore import QObject
-from PySide6.QtQml import ListProperty
+from helper.usesqapplication import UsesQApplication  # noqa: E402, F401
+
+from PySide6.QtCore import QObject, QUrl, Property, qInstallMessageHandler  # noqa: E402
+from PySide6.QtQml import ListProperty, QmlElement  # noqa: E402
+from PySide6.QtQuick import QQuickView  # noqa: E402
+
+
+QML_IMPORT_NAME = "test.ListPropertyTest"
+QML_IMPORT_MAJOR_VERSION = 1
+
+output_messages = []
+
+
+def message_handler(mode, context, message):
+    global output_messages
+    output_messages.append(f"{message}")
 
 
 class InheritsQObject(QObject):
@@ -22,7 +36,46 @@ def dummyFunc():
     pass
 
 
-class TestListProperty(unittest.TestCase):
+@QmlElement
+class Person(QObject):
+    def __init__(self, parent=None):
+        super().__init__(parent=None)
+        self._name = ''
+        self._friends = []
+
+    def appendFriend(self, friend):
+        self._friends.append(friend)
+
+    def friendCount(self):
+        return len(self._friends)
+
+    def friend(self, index):
+        return self._friends[index]
+
+    def removeLastItem(self):
+        if len(self._friends) > 0:
+            self._friends.pop()
+
+    def replace(self, index, friend):
+        if 0 <= index < len(self._friends):
+            self._friends[index] = friend
+
+    def clear(self):
+        self._friends.clear()
+
+    @Property(str, final=True)
+    def name(self):
+        return self._name
+
+    @name.setter
+    def name(self, value):
+        self._name = value
+
+    friends = ListProperty(QObject, append=appendFriend, count=friendCount, at=friend,
+                           removeLast=removeLastItem, replace=replace, clear=clear)
+
+
+class TestListProperty(UsesQApplication):
     def testIt(self):
 
         # Verify that type checking works properly
@@ -31,7 +84,7 @@ class TestListProperty(unittest.TestCase):
         try:
             ListProperty(QObject)
             ListProperty(InheritsQObject)
-        except:
+        except Exception:
             type_check_error = True
 
         self.assertFalse(type_check_error)
@@ -47,21 +100,37 @@ class TestListProperty(unittest.TestCase):
         method_check_error = False
 
         try:
-            ListProperty(QObject, append=None, at=None, count=None, replace=None, clear=None, removeLast=None)  # Explicitly setting None
+            ListProperty(QObject, append=None, at=None, count=None, replace=None, clear=None,
+                         removeLast=None)  # Explicitly setting None
             ListProperty(QObject, append=dummyFunc)
             ListProperty(QObject, count=dummyFunc, at=dummyFunc)
-        except:
+        except Exception:
             method_check_error = True
 
         self.assertFalse(method_check_error)
 
         try:
-            ListPropery(QObject, append=QObject())
-        except:
+            ListProperty(QObject, append=QObject())
+        except Exception:
             method_check_error = True
 
         self.assertTrue(method_check_error)
 
+    def testListPropParameters(self):
+        global output_messages
+        qInstallMessageHandler(message_handler)
+        view = QQuickView()
+        file = Path(__file__).resolve().parent / 'listproperty.qml'
+        self.assertTrue(file.is_file())
+        view.setSource(QUrl.fromLocalFile(file))
+        view.show()
+        self.assertEqual(output_messages[0], "List length: 3")
+        self.assertEqual(output_messages[1], "First element: Alice")
+        self.assertEqual(output_messages[2], "Removing last item: Charlie")
+        self.assertEqual(output_messages[3], "Replacing last item: Bob")
+        self.assertEqual(output_messages[4], "Replaced last item: David")
+        self.assertEqual(output_messages[5], "List length after clearing: 0")
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/sources/pyside6/tests/QtQml/listproperty.qml b/sources/pyside6/tests/QtQml/listproperty.qml
new file mode 100644 (file)
index 0000000..7b71e30
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick 2.0
+import test.ListPropertyTest
+
+Rectangle {
+    width: 360
+    height: 360
+
+    Person {
+        id: person
+        friends: [
+            Person{
+                name: "Alice"
+            },
+            Person{
+                name: "Bob"
+            },
+            Person{
+                name: "Charlie"
+            }
+        ]
+    }
+
+    Person{
+        id: david
+        name: "David"
+    }
+
+    Component.onCompleted: {
+        // Access the length of the list
+        console.log("List length: " + person.friends.length);
+
+        // Access the first element of the list
+        console.log("First element: " + person.friends[0].name);
+
+        // Remove the last item of the list
+        console.log("Removing last item: " + person.friends.pop().name);
+
+        // Repalce the last item of the list
+        console.log("Replacing last item: " + person.friends[person.friends.length - 1].name);
+        person.friends[person.friends.length - 1] = david;
+        console.log("Replaced last item: " + person.friends[person.friends.length - 1].name);
+
+        // Clear the list
+        person.friends = [];
+        console.log("List length after clearing: " + person.friends.length);
+    }
+}
diff --git a/sources/pyside6/tests/QtQml/qmlregistertype_test.py b/sources/pyside6/tests/QtQml/qmlregistertype_test.py
new file mode 100644 (file)
index 0000000..0042d6f
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.usesqapplication import UsesQApplication
+
+
+from PySide6.QtCore import QCoreApplication, QObject  # noqa: F401
+from PySide6.QtQml import QQmlApplicationEngine, qmlRegisterType
+
+
+class BaseClass(QObject):
+    def __init__(self, p=None):
+        super().__init__(p)
+
+
+class ChildClass(BaseClass):
+    def __init__(self, p=None):
+        super().__init__(p)
+
+
+class TestQmlRegisterType(UsesQApplication):
+    """Test the legacy QML register functions."""
+
+    def test(self):
+        qmlRegisterType(BaseClass, 'test', 1, 0, 'BaseClass')
+        qmlRegisterType(ChildClass, 'test', 1, 0, 'ChildClass')
+        # PYSIDE-2709: qmlRegisterType() would set additional class info
+        # on the meta objects for registration which caused another meta
+        # object to be created, breaking inheritance.
+        child = ChildClass()
+        base = BaseClass()
+        self.assertTrue(child.metaObject().inherits(base.metaObject()))
+
+        engine = QQmlApplicationEngine()
+        file = Path(__file__).resolve().parent / 'qmlregistertype_test.qml'
+
+        engine.load(file)
+        rootObjects = engine.rootObjects()
+        self.assertTrue(rootObjects)
+        self.assertTrue(type(rootObjects[0]), ChildClass)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/sources/pyside6/tests/QtQml/qmlregistertype_test.qml b/sources/pyside6/tests/QtQml/qmlregistertype_test.qml
new file mode 100644 (file)
index 0000000..108bb84
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import test
+
+ChildClass {
+}
index 492217fd62beebf8cf7b7f385c62e4eaf2875d4f..6beca11317f42ee065d188371e4d6fc3faac8961 100644 (file)
@@ -12,13 +12,18 @@ init_test_paths(False)
 
 from helper.helper import quickview_errorstring
 
-from PySide6.QtCore import Property, Signal, QTimer, QUrl, QObject
+from PySide6.QtCore import Property, Signal, QTimer, QUrl, QObject, Slot
 from PySide6.QtGui import QGuiApplication
 from PySide6.QtQml import (qmlRegisterSingletonType, qmlRegisterSingletonInstance,
-                           QmlElement, QmlSingleton)
+                           QmlElement, QmlSingleton, QJSValue)
 from PySide6.QtQuick import QQuickView
 
+
+URI = "Singletons"
+
+
 finalResult = 0
+qObjectQmlTypeId = 0
 
 
 class SingletonQObject(QObject):
@@ -46,7 +51,7 @@ def singletonQJSValueCallback(engine):
     return engine.evaluate("new Object({data: 50})")
 
 
-QML_IMPORT_NAME = "Singletons"
+QML_IMPORT_NAME = URI
 QML_IMPORT_MAJOR_VERSION = 1
 
 
@@ -66,37 +71,82 @@ class DecoratedSingletonQObject(QObject):
     data = Property(int, getData, setData)
 
 
+@QmlElement
+@QmlSingleton
+class DecoratedSingletonWithCreate(QObject):
+    def __init__(self, data, parent=None):
+        super().__init__(parent)
+        self._data = data
+
+    @staticmethod
+    def create(engine):
+        return DecoratedSingletonWithCreate(400)
+
+    def getData(self):
+        return self._data
+
+    def setData(self, data):
+        self._data = data
+
+    data = Property(int, getData, setData)
+
+
+class TestQuickView(QQuickView):
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self._singleton_instance_qobject_int = False
+        self._singleton_instance_qobject_str = False
+        self._singleton_instance_jsvalue_int = False
+
+    @Slot()
+    def testSlot(self):
+        engine = self.engine()
+        instance = engine.singletonInstance(qObjectQmlTypeId)
+        if instance is not None and isinstance(instance, QObject):
+            self._singleton_instance_qobject_int = True
+        instance = engine.singletonInstance(URI, 'SingletonQObjectNoCallback')
+        if instance is not None and isinstance(instance, QObject):
+            self._singleton_instance_qobject_str = True
+        instance = engine.singletonInstance(URI, 'SingletonQJSValue')
+        if instance is not None and isinstance(instance, QJSValue):
+            self._singleton_instance_jsvalue_int = True
+        self.close()
+
+
 class TestQmlSupport(unittest.TestCase):
     def testIt(self):
         app = QGuiApplication([])
 
-        qmlRegisterSingletonType(SingletonQObject, 'Singletons', 1, 0, 'SingletonQObjectNoCallback')
-        qmlRegisterSingletonType(SingletonQObject, 'Singletons', 1, 0, 'SingletonQObjectCallback',
+        qObjectQmlTypeId = qmlRegisterSingletonType(SingletonQObject, URI, 1, 0,
+                                                    'SingletonQObjectNoCallback')
+        qmlRegisterSingletonType(SingletonQObject, URI, 1, 0, 'SingletonQObjectCallback',
                                  singletonQObjectCallback)
 
-        qmlRegisterSingletonType('Singletons', 1, 0, 'SingletonQJSValue', singletonQJSValueCallback)
+        qmlRegisterSingletonType(URI, 1, 0, 'SingletonQJSValue', singletonQJSValueCallback)
 
         # Accepts only QObject derived types
         l = [1, 2]
         with self.assertRaises(TypeError):
-            qmlRegisterSingletonInstance(SingletonQObject, 'Singletons', 1, 0, 'SingletonInstance', l)
+            qmlRegisterSingletonInstance(SingletonQObject, URI, 1, 0, 'SingletonInstance', l)
 
         # Modify value on the instance
         s = SingletonQObject()
         s.setData(99)
-        qmlRegisterSingletonInstance(SingletonQObject, 'Singletons', 1, 0, 'SingletonInstance', s)
+        qmlRegisterSingletonInstance(SingletonQObject, URI, 1, 0, 'SingletonInstance', s)
 
-        view = QQuickView()
+        view = TestQuickView()
         file = Path(__file__).resolve().parent / 'registersingletontype.qml'
         self.assertTrue(file.is_file())
         view.setSource(QUrl.fromLocalFile(file))
         self.assertTrue(view.rootObject(), quickview_errorstring(view))
         view.resize(200, 200)
         view.show()
-        QTimer.singleShot(250, view.close)
+        QTimer.singleShot(250, view.testSlot)
         app.exec()
-        self.assertEqual(finalResult, 499)
+        self.assertEqual(finalResult, 899)
+        self.assertTrue(view._singleton_instance_qobject_int)
+        self.assertTrue(view._singleton_instance_qobject_str)
+        self.assertTrue(view._singleton_instance_jsvalue_int)
 
 
-if __name__ == '__main__':
-    unittest.main()
+if __name__ == '__main__':    unittest.main()
index 4c45b198e59feb123a04d34b9d58f8b898882fa9..31ca7fe4d49245074a076bf018ad275aeedae38f 100644 (file)
@@ -9,6 +9,6 @@ Item {
         SingletonQObjectCallback.data += SingletonQObjectNoCallback.data
             + SingletonQJSValue.data
             + SingletonInstance.data
-            + DecoratedSingletonQObject.data;
+            + DecoratedSingletonQObject.data + DecoratedSingletonWithCreate.data;
     }
 }
diff --git a/sources/pyside6/tests/QtQuickTest/CMakeLists.txt b/sources/pyside6/tests/QtQuickTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..49f15e4
--- /dev/null
@@ -0,0 +1,3 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+PYSIDE_TEST(quicktestmainwithsetup/tst_quicktestmainwithsetup.py)
diff --git a/sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/data/tst_setup.qml b/sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/data/tst_setup.qml
new file mode 100644 (file)
index 0000000..2cfe936
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.0
+import QtTest 1.2
+
+import QmlRegisterTypeCppModule 1.0
+import ImportPathQmlModule 1.0
+
+TestCase {
+    name: "setup"
+
+    QmlRegisterTypeCppType {}
+    ImportPathQmlType {}
+
+    function initTestCase()
+    {
+        verify(qmlEngineAvailableCalled)
+    }
+}
diff --git a/sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/imports/ImportPathQmlModule/ImportPathQmlType.qml b/sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/imports/ImportPathQmlModule/ImportPathQmlType.qml
new file mode 100644 (file)
index 0000000..617bdaa
--- /dev/null
@@ -0,0 +1,3 @@
+import QtQuick 2.0
+
+Item {}
diff --git a/sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/imports/ImportPathQmlModule/qmldir b/sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/imports/ImportPathQmlModule/qmldir
new file mode 100644 (file)
index 0000000..dea7c9a
--- /dev/null
@@ -0,0 +1,2 @@
+module ImportPathQmlModule
+ImportPathQmlType 1.0 ImportPathQmlType.qml
diff --git a/sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/quicktestmainwithsetup.pyproject b/sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/quicktestmainwithsetup.pyproject
new file mode 100644 (file)
index 0000000..61e89f4
--- /dev/null
@@ -0,0 +1,4 @@
+{
+    "files": ["tst_quicktestmainwithsetup.py", "data/tst_setup.qml",
+              "imports/ImportPathQmlModule/ImportPathQmlType.qml"]
+}
diff --git a/sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/tst_quicktestmainwithsetup.py b/sources/pyside6/tests/QtQuickTest/quicktestmainwithsetup/tst_quicktestmainwithsetup.py
new file mode 100644 (file)
index 0000000..33b2db0
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[2]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from pathlib import Path
+from PySide6.QtCore import QObject, Slot
+from PySide6.QtQml import QQmlEngine, qmlRegisterType
+from PySide6.QtQuickTest import QUICK_TEST_MAIN_WITH_SETUP
+
+
+"""Copy of the equivalent test in qtdeclarative."""
+
+
+class QmlRegisterTypeCppType(QObject):
+    def __init__(self, parent=None):
+        super().__init__(parent)
+
+
+class CustomTestSetup(QObject):
+    def __init__(self, parent=None):
+        super().__init__(parent)
+
+    @Slot(QQmlEngine)
+    def qmlEngineAvailable(self, qmlEngine):
+        # Test that modules are successfully imported by the TestCaseCollector
+        # that parses the QML files (but doesn't run them). For that to happen,
+        # qmlEngineAvailable() must be called before TestCaseCollector does its
+        # thing.
+        qmlRegisterType(QmlRegisterTypeCppType, "QmlRegisterTypeCppModule", 1, 0,
+                        "QmlRegisterTypeCppType")
+        import_dir = Path(__file__).parent / "imports"
+        qmlEngine.addImportPath(os.fspath(import_dir))
+        qmlEngine.rootContext().setContextProperty("qmlEngineAvailableCalled", True)
+
+
+data_dir = Path(__file__).parent / "data"
+exitCode = QUICK_TEST_MAIN_WITH_SETUP("qquicktestsetup", CustomTestSetup, sys.argv,
+                                      os.fspath(data_dir))
+sys.exit(exitCode)
index 54e0d6c3aba7130f8dea22d3411bf8e395e9ae85..01b7d08ea258b2e9be3f67c479d280379e8e7aed 100644 (file)
@@ -84,6 +84,7 @@ PYSIDE_TEST(qapp_issue_585.py)
 PYSIDE_TEST(qapp_test.py)
 PYSIDE_TEST(qapplication_test.py)
 PYSIDE_TEST(qapplication_exit_segfault_test.py)
+PYSIDE_TEST(qdialog_test.py)
 PYSIDE_TEST(qdynamic_signal.py)
 # TODO: This passes, but requires manual button clicking (at least on mac)
 #PYSIDE_TEST(qfontdialog_test.py)
diff --git a/sources/pyside6/tests/QtWidgets/qdialog_test.py b/sources/pyside6/tests/QtWidgets/qdialog_test.py
new file mode 100644 (file)
index 0000000..cb85ce7
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+import weakref
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from PySide6.QtCore import Slot, QTimer
+from PySide6.QtWidgets import QDialog, QMainWindow
+from helper.timedqapplication import TimedQApplication
+
+
+class Window(QMainWindow):
+    def __init__(self):
+        super().__init__()
+        self.setWindowTitle("Main")
+        self.dialog = None
+
+    @Slot()
+    def execDialog(self):
+        dialog = QDialog(self)
+        self.dialog = weakref.ref(dialog)
+        dialog.setWindowTitle("Dialog")
+        dialog.setMinimumWidth(200)
+        QTimer.singleShot(500, dialog.reject)
+        dialog.exec()
+        self.close()
+
+
+class DialogExecTest(TimedQApplication):
+    """Test whether the parent-child relationship (dialog/main window) is removed when
+       using QDialog.exec() (instead show()), preventing the dialog from leaking."""
+
+    def setUp(self):
+        super().setUp(10000)
+        self._window = Window()
+
+    def testExec(self):
+        self._window.show()
+        QTimer.singleShot(500, self._window.execDialog)
+        self.app.exec()
+        self.assertTrue(self._window.dialog() is None)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/sources/pyside6/tests/manually/lazytiming.py b/sources/pyside6/tests/manually/lazytiming.py
new file mode 100644 (file)
index 0000000..59f75bc
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""
+Time a repeated Python run
+--------------------------
+
+Usage: python3 lazytiming.py              # uses PySide6
+       python3 lazytiming.py <any arg>    # uses PyQt6
+
+It runs the same python for the testing.
+
+Actually comparing PySide6 and PyQt6 in action:
+
+    PYSIDE6_OPTION_LAZY=0 python3 sources/pyside6/tests/manually/lazytiming.py      # normal
+    PYSIDE6_OPTION_LAZY=1 python3 sources/pyside6/tests/manually/lazytiming.py      # faster
+                          python3 sources/pyside6/tests/manually/lazytiming.py xxx  # PyQt
+"""
+import subprocess
+import sys
+
+from timeit import default_timer as timer
+
+repeats = 100
+test1 = "PySide6"
+test2 = "PyQt6"
+
+test = test2 if sys.argv[1:] else test1
+cmd = [sys.executable, "-c", f"from {test} import QtCore, QtGui, QtWidgets"]
+
+print(f"{repeats} * {test}")
+
+subprocess.call(cmd)        # warmup
+start_time = timer()
+for idx in range(repeats):
+    subprocess.call(cmd)
+stop_time = timer()
+print(f"time per run = {(stop_time - start_time) / repeats}")
index 6dc56735db7c7803227d79dc30c99df12703f8b9..38f42f3425e631f73b045d1bd0809200f5750736 100644 (file)
@@ -46,6 +46,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/testbinding/sharedpointertestbench_wrapper.cpp
 ${CMAKE_CURRENT_BINARY_DIR}/testbinding/testview_wrapper.cpp
 ${CMAKE_CURRENT_BINARY_DIR}/testbinding/testbinding_module_wrapper.cpp
 ${CMAKE_CURRENT_BINARY_DIR}/testbinding/testqvariantenum_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/testbinding/qvariantholder_wrapper.cpp
 )
 
 # Get per module include dirs.
index fe8e14f9f7f7c87e6a840305a85e4a04fce051bc..49550ba55f8137c5b55ab1fe9089079a2ac8cc90 100644 (file)
@@ -12,7 +12,7 @@ init_test_paths(False)
 
 from helper.usesqapplication import UsesQApplication
 from PySide6 import QtCore, QtGui, QtWidgets
-from PySide6.QtWidgets import QMainWindow, QLabel
+from PySide6.QtWidgets import QMainWindow, QLabel, QWidget
 
 
 def xprint(*args, **kw):
@@ -71,7 +71,8 @@ class C(A, B):
         xprint('C: after init')
 
 
-# mro ('F', 'D', 'QCursor', 'E', 'QLabel', 'QFrame', 'QWidget', 'QObject', 'QPaintDevice', 'Object', 'object')
+# mro ('F', 'D', 'QCursor', 'E', 'QLabel', 'QFrame', 'QWidget', 'QObject',
+#      'QPaintDevice', 'Object', 'object')
 class D(QtGui.QCursor):
     def __init__(self, anna=77, **kw):
         xprint(f'D: before init kw = {kw}')
@@ -94,7 +95,8 @@ class F(D, E, QtWidgets.QLabel):
         xprint('F: after init')
 
 
-# mro ('I', 'G', 'QTextDocument', 'H', 'QLabel', 'QFrame', 'QWidget', 'QObject', 'QPaintDevice', 'Object', 'object')
+# mro ('I', 'G', 'QTextDocument', 'H', 'QLabel', 'QFrame', 'QWidget', 'QObject',
+#      'QPaintDevice', 'Object', 'object')
 # Similar, but this time we want to reach `H` without support from `super`.
 class G(QtGui.QTextDocument):
     pass
@@ -108,7 +110,7 @@ class H:
         xprint('H: after init')
 
 
-class I(G, H, QtWidgets.QLabel):
+class II(G, H, QtWidgets.QLabel):
     pass
 
 
@@ -145,7 +147,7 @@ class AdditionalMultipleInheritanceTest(UsesQApplication):
 
     def testGHI(self):
         xprint()
-        res = I(age=7)
+        res = II(age=7)
         self.assertEqual(res.age, 7)
         xprint()
 
@@ -155,5 +157,33 @@ class AdditionalMultipleInheritanceTest(UsesQApplication):
         MainWindow()
 
 
+# PYSIDE-2654: Additional missing init test.
+#              This must work if no __init__ is defined (Ui_Form)
+class Ui_Form(object):
+    pass
+
+
+class Mixin:
+    def __init__(self, **kwargs) -> None:
+        super().__init__(**kwargs)
+
+
+class Card(Mixin, QWidget):
+    def __init__(self, parent=None) -> None:
+        super().__init__(parent=parent)
+
+
+class Demo(Card, Ui_Form):
+    def __init__(self) -> None:
+        super().__init__()
+
+
+class MissingInitFunctionTest(UsesQApplication):
+    def testMissing(self):
+        Demo()
+        # Tests if this works. Would crash without the extra
+        # check for object.__init__
+
+
 if __name__ == "__main__":
     unittest.main()
index 79ac446e3e159d967166a7a6d07972b5902d1058..faefc8169786afe2fcc811268786e4f11bdfb4ac 100644 (file)
@@ -26,8 +26,8 @@ class PyTestQVariantEnum(TestQVariantEnum):
         return Qt.Orientation.Vertical
 
     def channelingEnum(self, rval_enum):
-        return (isinstance(rval_enum, enum.Enum) and
-                rval_enum == Qt.Orientation.Vertical)
+        return (isinstance(rval_enum, enum.Enum)
+                and rval_enum == Qt.Orientation.Vertical)
 
 
 class QVariantTest(UsesQApplication):
@@ -43,8 +43,6 @@ class QVariantTest(UsesQApplication):
         QAction().setShortcut(Qt.CTRL | Qt.AltModifier | Qt.Key_B)
         QAction().setShortcut(QKeySequence(QKeyCombination(Qt.CTRL | Qt.Key_B)))
         QKeySequence(Qt.CTRL | Qt.Key_Q)
-        # Issues a warning but works as well
-        QKeySequence(Qt.CTRL + Qt.Key_Q)
 
     def testEnum(self):
         # Testing C++ class
index 01cc36b3771a33f2beb7eec0d1ae5ec0331f49b5..863f17657d335e10c4d690872933e277a188348f 100644 (file)
@@ -49,6 +49,15 @@ class QObjectDerivedReprTest(unittest.TestCase):
         # __repr__ should use the operator<<(QDebug,...) implementation
         self.assertEqual(str(t), "TestObject2WithNamespace(injected_repr)")
 
+    def testLatin1StringField(self):
+        self.assertEqual(TestObject.LATIN1_TEST_FIELD, "test")
+
+    def testLatin1Setter(self):
+        to = TestObject(123)
+        value = "test"
+        to.setQLatin1String(value)
+        self.assertEqual(to.qLatin1String(), value)
+
 
 if __name__ == '__main__':
     unittest.main()
index cf09b296411722253804bb2c21ea34f3fcf9f157..744b8c503b09069102dbf8b0503494b5b999327b 100644 (file)
@@ -13,7 +13,7 @@ from init_paths import init_test_paths
 init_test_paths(True)
 
 from testbinding import TestObject
-from PySide6.QtCore import QObject, SIGNAL
+from PySide6.QtCore import Qt
 
 '''Tests the behaviour of signals with default values.'''
 
@@ -56,6 +56,17 @@ class SignalWithDefaultValueTest(unittest.TestCase):
         self.assertTrue(self.void_called)
         self.assertTrue(self.bool_called)
 
+    def testFlagsSignal(self):
+        test_value = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignBottom
+
+        def callbackAlignmentFlags(alignment):
+            self.alignment_flags_called = alignment
+
+        self.obj.flagsSignal.connect(callbackAlignmentFlags)
+        self.obj.emitFlagsSignal(test_value)
+        self.assertTrue(self.alignment_flags_called)
+        self.assertEqual(self.alignment_flags_called, test_value)
+
     def testConnectOldStyleEmitVoidSignal(self):
         def callbackVoid():
             self.void_called = True
@@ -83,4 +94,3 @@ class SignalWithDefaultValueTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 2233bad62b2b2a420abd1c3516ba541b0e5527d7..fe4ec98f72116f112f7a019e497ad50fa3748604 100644 (file)
@@ -30,6 +30,26 @@ void TestObject::emitSignalWithTypedefValue(int value)
     emit signalWithTypedefValue(TypedefValue(value));
 }
 
+void TestObject::emitSignalWithContainerTypedefValue(const IntList &il)
+{
+    emit signalWithContainerTypedefValue(il);
+}
+
+void TestObject::emitFlagsSignal(Qt::Alignment alignment)
+{
+    emit flagsSignal(alignment);
+}
+
+void TestObject::setQLatin1String(QLatin1String v)
+{
+    m_qLatin1String = v;
+}
+
+QString TestObject::qLatin1String() const
+{
+    return m_qLatin1String;
+}
+
 QDebug operator<<(QDebug dbg, TestObject& testObject)
 {
     QDebugStateSaver saver(dbg);
index d3f0b20189379bb32e9690852faebc8c606919db..a095a382ebd42d6de2fd51686c44ffb2f1e5fc56 100644 (file)
@@ -8,12 +8,15 @@
 
 #include <QtWidgets/QApplication>
 
+#include <QtCore/QList>
 #include <QtCore/QObject>
 #include <QtCore/QMetaType>
 #include <QtCore/QVariant>
 
 QT_FORWARD_DECLARE_CLASS(QDebug)
 
+using IntList = QList<int>;
+
 class IntValue
 {
 public:
@@ -44,6 +47,14 @@ public:
     void emitSignalWithDefaultValue_bool();
 
     void emitSignalWithTypedefValue(int value);
+    void emitSignalWithContainerTypedefValue(const IntList &il);
+
+    void emitFlagsSignal(Qt::Alignment alignment);
+
+    static constexpr auto LATIN1_TEST_FIELD = QLatin1StringView("test");
+
+    void setQLatin1String(QLatin1String v);
+    QString qLatin1String() const;
 
 signals:
     void idValue(int newValue);
@@ -52,10 +63,13 @@ signals:
     void childrenChanged(const QList<QObject*>&);
     void signalWithDefaultValue(bool value = false);
     void signalWithTypedefValue(TypedefValue value);
+    void signalWithContainerTypedefValue(const IntList &il);
+    void flagsSignal(Qt::Alignment alignment);
 
 private:
     int m_idValue;
     QList<QObject*> m_children;
+    QString m_qLatin1String;
 };
 
 PYSIDETEST_API QDebug operator<<(QDebug dbg, TestObject &testObject);
index 46564d2684f53c734149e82b670318f87ff9d805..4b729e3dd6a908239cc3f981205fcd2462996b0d 100644 (file)
@@ -22,4 +22,14 @@ private:
     QVariant m_enum;
 };
 
+class PYSIDETEST_API QVariantHolder // modeled after Q3DParameter, test QVariant conversion
+{
+public:
+    void setValue(QVariant v) { m_variant = v; }
+    QVariant value() const { return m_variant; }
+
+private:
+    QVariant m_variant;
+};
+
 #endif // TESTQVARIANT_H
index dfe5311e8cc5538b56dc603e32a22a07f1300e03..d0bdc880b66ed996d4c6968dbf2a091152be1924 100644 (file)
@@ -10,7 +10,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(True)
 
-from PySide6.QtCore import QObject
+from PySide6.QtCore import QObject, Slot
 from testbinding import TestObject
 
 
@@ -23,6 +23,10 @@ class Receiver(QObject):
     def slot(self, value):
         self.received = value
 
+    @Slot("IntList")
+    def containerSlot(self, value):
+        self.received = value
+
 
 class TypedefSignal(unittest.TestCase):
 
@@ -34,6 +38,15 @@ class TypedefSignal(unittest.TestCase):
         obj.emitSignalWithTypedefValue(2)
         self.assertEqual(receiver.received.value, 2)
 
+    def testContainerTypedef(self):
+        obj = TestObject(0)
+        receiver = Receiver()
+
+        test_list = [1, 2]
+        obj.signalWithContainerTypedefValue.connect(receiver.containerSlot)
+        obj.emitSignalWithContainerTypedefValue(test_list)
+        self.assertEqual(receiver.received, test_list)
+
 
 if __name__ == '__main__':
     unittest.main()
index bd959f7e3454a94c2926e3d7296355b1f6857886..592d90a8385a63240ca519a545ecab2e1e87211f 100644 (file)
@@ -72,6 +72,8 @@
 
     <object-type name="SharedPointerTestbench"/>
 
+    <value-type name="QVariantHolder"/>
+
     <smart-pointer-type name="QSharedPointer" type="shared" getter="data"
                         reset-method="reset"/>
 
index a1c5e05e59dbfc182a6d5571f547c8c24aee0c82..5d81926a118778a9fb73c738378d975e1d58c870 100644 (file)
@@ -71,14 +71,8 @@ def linux_distribution():
     # distro package, ASAP! The distro has been extracted from Python,
     # because it changes more often than the Python version.
     distribution = []
-    try:
-        import distro
-        distribution = distro.linux_distribution()
-    except ImportError:
-        # platform.linux_distribution() was removed in 3.8
-        if sys.version_info[:2] < (3, 8):
-            import platform
-            distribution = platform.linux_distribution()
+    import distro
+    distribution = distro.linux_distribution()
     if distribution:
         return "".join(distribution[:2]).lower()
     warnings.warn('Cannot determine Linux distribution, please install distro',
index 96946c0028cb4bfb7f60a59dd72b7d215c61c971..ff342adc73e85a0dd421fb325f9ae4aea058d2b6 100644 (file)
@@ -16,6 +16,7 @@ PYSIDE_TEST(leaking_signal_test.py)
 PYSIDE_TEST(multiple_connections_gui_test.py)
 PYSIDE_TEST(multiple_connections_test.py)
 PYSIDE_TEST(pysignal_test.py)
+PYSIDE_TEST(qobject_callable_connect_test.py)
 PYSIDE_TEST(qobject_destroyed_test.py)
 PYSIDE_TEST(qobject_receivers_test.py)
 PYSIDE_TEST(qobject_sender_test.py)
index e200cedbc027abca9cb0284ced9e1c2c290673e8..4f56be348812203d0c0cda9b2bcc8575f0989974 100644 (file)
@@ -11,7 +11,11 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL
+from PySide6.QtCore import QObject, Signal
+
+
+class Sender(QObject):
+    the_signal = Signal(int, int, int)
 
 
 class ArgsDontMatch(unittest.TestCase):
@@ -21,9 +25,9 @@ class ArgsDontMatch(unittest.TestCase):
 
     def testConnectSignalToSlotWithLessArgs(self):
         self.ok = False
-        obj1 = QObject()
-        QObject.connect(obj1, SIGNAL('the_signal(int, int, int)'), self.callback)
-        obj1.emit(SIGNAL('the_signal(int, int, int)'), 1, 2, 3)
+        obj1 = Sender()
+        obj1.the_signal.connect(self.callback)
+        obj1.the_signal.emit(1, 2, 3)
 
         self.assertTrue(self.ok)
 
index f2bbbc09303899695405decf02f61c2b716e8af2..e27476172543055e3e1268f41124ec15a4cd1808 100644 (file)
@@ -52,4 +52,3 @@ class SignaltoSignalTest(UsesQApplication):
 
 if __name__ == '__main__':
     unittest.main()
-
index de1a2f6a8ec7749cd7c84544f9a816435f2f0de6..80d56a0205cf1084d2a69c83d2038b243fb431cf 100644 (file)
@@ -11,44 +11,29 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL
+from PySide6.QtCore import QObject, Signal
 
 MAX_LOOPS = 5
 MAX_OBJECTS = 200
 
 
-class Dummy(object):
-    def __init__(self, parent):
-        self._parent = parent
-
-    def callback(self):
-        self._called = True
+class Sender(QObject):
+    fire = Signal()
 
 
 class MultipleSlots(unittest.TestCase):
     def myCB(self):
         self._count += 1
 
-    """
-    def testUnboundSignal(self):
-        o = QObject()
-        self._count  = 0
-        for i in range(MAX_OBJECTS):
-            QObject.connect(o, SIGNAL("fire()"), lambda: self.myCB())
-
-        o.emit(SIGNAL("fire()"))
-        self.assertEqual(self._count, MAX_OBJECTS)
-
-    """
     def testDisconnectCleanup(self):
         for c in range(MAX_LOOPS):
             self._count = 0
             self._senders = []
             for i in range(MAX_OBJECTS):
-                o = QObject()
-                QObject.connect(o, SIGNAL("fire()"), lambda: self.myCB())
+                o = Sender()
+                o.fire.connect(lambda: self.myCB())
                 self._senders.append(o)
-                o.emit(SIGNAL("fire()"))
+                o.fire.emit()
 
             self.assertEqual(self._count, MAX_OBJECTS)
 
@@ -58,5 +43,3 @@ class MultipleSlots(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
-
index bae0d8fdb84221614ddd866f5e671d42c3f9c3b1..657733afb3db214751311d8f122f6316dcb30e22 100644 (file)
@@ -45,4 +45,3 @@ class SignaltoSignalTest(UsesQApplication):
 
 if __name__ == '__main__':
     unittest.main()
-
index 0e12301f27ac17e5813f44d80c3274443799ba17..77ac621d5a35c890cb573d2b85290322d2c699b4 100644 (file)
@@ -30,7 +30,7 @@ class ConnectTest(unittest.TestCase):
 
     def testNoLeaks_ConnectAndDisconnect(self):
         self._called = None
-        app = QApplication([])
+        app = QApplication([])  # noqa: F841
         o = QTreeView()
         o.setModel(QStandardItemModel())
         o.selectionModel().destroyed.connect(self.callback)
index 5b3b5469062aa12b8758035fba7722ee7f5bdfa6..b29339ee49450e51647f6b2da43e0eeb0d668843 100644 (file)
@@ -11,7 +11,11 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, Slot, SIGNAL, SLOT
+from PySide6.QtCore import QObject, Slot, Signal
+
+
+class Sender(QObject):
+    mySignal = Signal()
 
 
 class MyObject(QObject):
@@ -57,9 +61,10 @@ class StaticMetaObjectTest(unittest.TestCase):
         self.assertTrue(m.indexOfSlot('mySlot4(QString,int)') > 0)
 
     def testEmission(self):
+        sender = Sender()
         o = MyObject()
-        o.connect(SIGNAL("mySignal()"), o, SLOT("mySlot()"))
-        o.emit(SIGNAL("mySignal()"))
+        sender.mySignal.connect(o.mySlot)
+        sender.mySignal.emit()
         self.assertTrue(o._slotCalledCount == 1)
 
     def testResult(self):
index b5252870c26bfde5d0cbae698f51cab5feaa4734..2788c1d1af55901eb9e0adedd6cda52116e2f40b 100644 (file)
@@ -13,7 +13,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL
+from PySide6.QtCore import QObject
 
 
 class InvalidCallback(unittest.TestCase):
@@ -34,10 +34,8 @@ class InvalidCallback(unittest.TestCase):
 
     def testIntegerCb(self):
         # Test passing an int as callback to QObject.connect
-        self.assertRaises(TypeError, QObject.connect, self.obj,
-                          SIGNAL('destroyed()'), 42)
+        self.assertRaises(TypeError, self.obj.destroyed.connect, 42)
 
 
 if __name__ == '__main__':
     unittest.main()
-
index 45a6d6acf4605fa14307221064ba439640a0ff9c..2123e720686a8f8ee8d1f4f2acebe3ddcc81e0f5 100644 (file)
@@ -12,43 +12,39 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL
-
-try:
-    from PySide6.QtWidgets import QSpinBox, QPushButton
-    hasQtGui = True
-except ImportError:
-    hasQtGui = False
+from PySide6.QtWidgets import QSpinBox, QPushButton
 
 from helper.usesqapplication import UsesQApplication
 
-if hasQtGui:
-    class Control:
-        def __init__(self):
-            self.arg = False
-
-    class QtGuiSigLambda(UsesQApplication):
-
-        def testButton(self):
-            # Connecting a lambda to a QPushButton.clicked()
-            obj = QPushButton('label')
-            ctr = Control()
-            func = lambda: setattr(ctr, 'arg', True)
-            obj.clicked.connect(func)
-            obj.click()
-            self.assertTrue(ctr.arg)
-            QObject.disconnect(obj, SIGNAL('clicked()'), func)
-
-        def testSpinButton(self):
-            # Connecting a lambda to a QPushButton.clicked()
-            obj = QSpinBox()
-            ctr = Control()
-            arg = 444
-            func = lambda x: setattr(ctr, 'arg', 444)
-            obj.valueChanged.connect(func)
-            obj.setValue(444)
-            self.assertEqual(ctr.arg, arg)
-            QObject.disconnect(obj, SIGNAL('valueChanged(int)'), func)
+
+class Control:
+    def __init__(self):
+        self.arg = False
+
+
+class QtWidgetsSigLambda(UsesQApplication):
+
+    def testButton(self):
+        # Connecting a lambda to a QPushButton.clicked()
+        obj = QPushButton('label')
+        ctr = Control()
+        func = lambda: setattr(ctr, 'arg', True)  # noqa: E731
+        obj.clicked.connect(func)
+        obj.click()
+        self.assertTrue(ctr.arg)
+        self.assertTrue(obj.clicked.disconnect(func))
+
+    def testSpinButton(self):
+        # Connecting a lambda to a QPushButton.clicked()
+        obj = QSpinBox()
+        ctr = Control()
+        arg = 444
+        func = lambda x: setattr(ctr, 'arg', 444)  # noqa: E731
+        obj.valueChanged.connect(func)
+        obj.setValue(444)
+        self.assertEqual(ctr.arg, arg)
+        self.assertTrue(obj.valueChanged.disconnect(func))
+
 
 if __name__ == '__main__':
     unittest.main()
index a91a979595e150ec9ea4208bf79607a2767ce53d..23fcdf5fab43e52dea5ed2ad974169faff164f7d 100644 (file)
@@ -7,18 +7,34 @@
 import os
 import sys
 import unittest
+import weakref
 
 from pathlib import Path
 sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, QProcess
+from PySide6.QtCore import QCoreApplication, QObject, Signal, SIGNAL, QProcess
 
 from helper.usesqapplication import UsesQApplication
 
 
-class Dummy(QObject):
+class Sender(QObject):
+    void_signal = Signal()
+    int_signal = Signal(int)
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self._delayed_int = 0
+
+    def emit_void(self):
+        self.void_signal.emit()
+
+    def emit_int(self, v):
+        self.int_signal.emit(v)
+
+
+class Receiver(QObject):
 
     def __init__(self, *args):
         super().__init__(*args)
@@ -28,45 +44,79 @@ class BasicCase(unittest.TestCase):
 
     def testSimplePythonSignalNoArgs(self):
         # Connecting a lambda to a simple python signal without arguments
-        obj = Dummy()
-        QObject.connect(obj, SIGNAL('foo()'),
-                        lambda: setattr(obj, 'called', True))
-        obj.emit(SIGNAL('foo()'))
-        self.assertTrue(obj.called)
+        receiver = Receiver()
+        sender = Sender()
+        sender.void_signal.connect(lambda: setattr(receiver, 'called', True))
+        sender.emit_void()
+        self.assertTrue(receiver.called)
 
     def testSimplePythonSignal(self):
         # Connecting a lambda to a simple python signal witharguments
-        obj = Dummy()
+        receiver = Receiver()
+        sender = Sender()
+        arg = 42
+        sender.int_signal.connect(lambda x: setattr(receiver, 'arg', arg))
+        sender.emit_int(arg)
+        self.assertEqual(receiver.arg, arg)
+
+    def testSimplePythonSignalNoArgsString(self):
+        # Connecting a lambda to a simple python signal without arguments
+        receiver = Receiver()
+        sender = Sender()
+        QObject.connect(sender, SIGNAL('void_signal()'),
+                        lambda: setattr(receiver, 'called', True))
+        sender.emit_void()
+        self.assertTrue(receiver.called)
+
+    def testSimplePythonSignalString(self):
+        # Connecting a lambda to a simple python signal witharguments
+        receiver = Receiver()
+        sender = Sender()
         arg = 42
-        QObject.connect(obj, SIGNAL('foo(int)'),
-                        lambda x: setattr(obj, 'arg', 42))
-        obj.emit(SIGNAL('foo(int)'), arg)
-        self.assertEqual(obj.arg, arg)
+        QObject.connect(sender, SIGNAL('int_signal(int)'),
+                        lambda x: setattr(receiver, 'arg', arg))
+        sender.emit_int(arg)
+        self.assertEqual(receiver.arg, arg)
 
 
 class QtSigLambda(UsesQApplication):
 
     qapplication = True
 
-    def testNoArgs(self):
-        '''Connecting a lambda to a signal without arguments'''
-        proc = QProcess()
-        dummy = Dummy()
-        QObject.connect(proc, SIGNAL('started()'),
-                        lambda: setattr(dummy, 'called', True))
-        proc.start(sys.executable, ['-c', '""'])
-        proc.waitForFinished()
-        self.assertTrue(dummy.called)
-
     def testWithArgs(self):
-        '''Connecting a lambda to a signal with arguments'''
+        '''Connecting a lambda to a signal with and without arguments'''
         proc = QProcess()
-        dummy = Dummy()
-        QObject.connect(proc, SIGNAL('finished(int)'),
-                        lambda x: setattr(dummy, 'called', x))
+        dummy = Receiver()
+        proc.started.connect(lambda: setattr(dummy, 'called', True))
+        proc.finished.connect(lambda x: setattr(dummy, 'exit_code', x))
+
         proc.start(sys.executable, ['-c', '""'])
-        proc.waitForFinished()
-        self.assertEqual(dummy.called, proc.exitCode())
+        self.assertTrue(proc.waitForStarted())
+        self.assertTrue(proc.waitForFinished())
+
+        self.assertTrue(dummy.called)
+        self.assertEqual(dummy.exit_code, proc.exitCode())
+
+    def testRelease(self):
+        """PYSIDE-2646: Test whether main thread target slot lambda/methods
+           (and their captured objects) are released by the signal manager
+           after a while."""
+
+        def do_connect(sender):
+            receiver = Receiver()
+            sender.void_signal.connect(lambda: setattr(receiver, 'called', True))
+            return receiver
+
+        sender = Sender()
+        receiver = weakref.ref(do_connect(sender))
+        sender.emit_void()
+        self.assertTrue(receiver().called)
+        del sender
+        for i in range(3):
+            if not receiver():
+                break
+            QCoreApplication.processEvents()
+        self.assertFalse(receiver())
 
 
 if __name__ == '__main__':
index e7aff9628408fe5b452e3433e2d80c921857f48e..666ae7a1333d2e77d65630ca85df69d8c609d450 100644 (file)
@@ -4,7 +4,6 @@
 import os
 import sys
 import unittest
-import weakref
 
 from pathlib import Path
 sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
@@ -21,7 +20,7 @@ class LeakingSignal(unittest.TestCase):
         class Emitter(QObject):
             my_signal = Signal(object)
 
-        emitter = Emitter()
+        emitter = Emitter()  # noqa: F841
 
 
 if __name__ == '__main__':
index 097811750862ebac12e07b7366bcdc5b9489cf29..295369b7deba84a9476cde848f05cf872b039d92 100644 (file)
@@ -1,9 +1,7 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
-from functools import partial
 import os
-import random
 import sys
 import unittest
 
@@ -12,22 +10,16 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL
-
-try:
-    from PySide6.QtWidgets import QPushButton, QSpinBox
-    hasQtGui = True
-except ImportError:
-    hasQtGui = False
+from PySide6.QtWidgets import QPushButton, QSpinBox
 
 from helper.basicpyslotcase import BasicPySlotCase
 from helper.usesqapplication import UsesQApplication
 
 
-class MultipleSignalConnections(unittest.TestCase):
-    '''Base class for multiple signal connection testing'''
+class QtGuiMultipleSlots(UsesQApplication):
+    '''Multiple connections to QtGui signals'''
 
-    def run_many(self, sender, signal, emitter, receivers, args=None):
+    def run_many(self, signal, emitter, receivers, args=None):
         """Utility method to connect a list of receivers to a signal.
         sender - QObject that will emit the signal
         signal - string with the signal signature
@@ -41,7 +33,7 @@ class MultipleSignalConnections(unittest.TestCase):
 
         for rec in receivers:
             rec.setUp()
-            QObject.connect(sender, SIGNAL(signal), rec.cb)
+            signal.connect(rec.cb)
             rec.args = tuple(args)
 
         emitter(*args)
@@ -49,24 +41,20 @@ class MultipleSignalConnections(unittest.TestCase):
         for rec in receivers:
             self.assertTrue(rec.called)
 
+    def testButtonClick(self):
+        """Multiple connections to QPushButton.clicked()"""
+        sender = QPushButton('button')
+        receivers = [BasicPySlotCase() for x in range(30)]
+        self.run_many(sender.clicked, sender.click, receivers)
 
-if hasQtGui:
-    class QtGuiMultipleSlots(UsesQApplication, MultipleSignalConnections):
-        '''Multiple connections to QtGui signals'''
-
-        def testButtonClick(self):
-            """Multiple connections to QPushButton.clicked()"""
-            sender = QPushButton('button')
-            receivers = [BasicPySlotCase() for x in range(30)]
-            self.run_many(sender, 'clicked()', sender.click, receivers)
+    def testSpinBoxValueChanged(self):
+        """Multiple connections to QSpinBox.valueChanged(int)"""
+        sender = QSpinBox()
+        # FIXME if number of receivers if higher than 50, segfaults
+        receivers = [BasicPySlotCase() for x in range(10)]
+        self.run_many(sender.valueChanged, sender.setValue,
+                      receivers, (1,))
 
-        def testSpinBoxValueChanged(self):
-            """Multiple connections to QSpinBox.valueChanged(int)"""
-            sender = QSpinBox()
-            # FIXME if number of receivers if higher than 50, segfaults
-            receivers = [BasicPySlotCase() for x in range(10)]
-            self.run_many(sender, 'valueChanged(int)', sender.setValue,
-                          receivers, (1,))
 
 if __name__ == '__main__':
     unittest.main()
index b6aa33f2d78339c03129d9839cb83ce6f16aa9a9..2338517979b07b6502bcb29d6e8e189a3b25b9a4 100644 (file)
@@ -11,7 +11,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, QProcess
+from PySide6.QtCore import QObject, Signal, QProcess
 
 from helper.basicpyslotcase import BasicPySlotCase
 from helper.usesqapplication import UsesQApplication
@@ -20,7 +20,7 @@ from helper.usesqapplication import UsesQApplication
 class MultipleSignalConnections(unittest.TestCase):
     '''Base class for multiple signal connection testing'''
 
-    def run_many(self, sender, signal, emitter, receivers, args=None):
+    def run_many(self, signal, emitter, receivers, args=None):
         """Utility method to connect a list of receivers to a signal.
         sender - QObject that will emit the signal
         signal - string with the signal signature
@@ -33,7 +33,7 @@ class MultipleSignalConnections(unittest.TestCase):
             args = tuple()
         for rec in receivers:
             rec.setUp()
-            self.assertTrue(QObject.connect(sender, SIGNAL(signal), rec.cb))
+            self.assertTrue(signal.connect(rec.cb))
             rec.args = tuple(args)
 
         emitter(*args)
@@ -48,13 +48,14 @@ class PythonMultipleSlots(UsesQApplication, MultipleSignalConnections):
     def testPythonSignal(self):
         """Multiple connections to a python signal (short-circuit)"""
 
-        class Dummy(QObject):
-            pass
+        class Sender(QObject):
 
-        sender = Dummy()
+            foobar = Signal(int)
+
+        sender = Sender()
         receivers = [BasicPySlotCase() for x in range(10)]
-        self.run_many(sender, 'foobar(int)', partial(sender.emit,
-                      SIGNAL('foobar(int)')), receivers, (0, ))
+        self.run_many(sender.foobar, partial(sender.foobar.emit),
+                      receivers, (0, ))
 
 
 class QProcessMultipleSlots(UsesQApplication, MultipleSignalConnections):
@@ -67,9 +68,10 @@ class QProcessMultipleSlots(UsesQApplication, MultipleSignalConnections):
 
         def start_proc(*args):
             sender.start(sys.executable, ['-c', '""'])
-            sender.waitForFinished()
+            self.assertTrue(sender.waitForStarted())
+            self.assertTrue(sender.waitForFinished())
 
-        self.run_many(sender, 'started()', start_proc, receivers)
+        self.run_many(sender.started, start_proc, receivers)
 
     def testQProcessFinished(self):
         '''Multiple connections to QProcess.finished(int)'''
@@ -78,9 +80,10 @@ class QProcessMultipleSlots(UsesQApplication, MultipleSignalConnections):
 
         def start_proc(*args):
             sender.start(sys.executable, ['-c', '""'])
-            sender.waitForFinished()
+            self.assertTrue(sender.waitForStarted())
+            self.assertTrue(sender.waitForFinished())
 
-        self.run_many(sender, 'finished(int)', start_proc, receivers, (0,))
+        self.run_many(sender.finished, start_proc, receivers, (0, QProcess.ExitStatus.NormalExit))
 
 
 if __name__ == '__main__':
index e3d6a55da1a9bb6b7a674e46861089ae121231b8..d6f44edf859951659e84204a11d94e956c5234c6 100644 (file)
@@ -11,31 +11,31 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, SLOT, Qt
-
-try:
-    from PySide6.QtWidgets import QSpinBox, QApplication, QWidget
-    hasQtGui = True
-except ImportError:
-    hasQtGui = False
+from PySide6.QtCore import QObject, Signal, Qt
+from PySide6.QtWidgets import QSpinBox, QApplication, QWidget  # noqa: F401
 
 from helper.usesqapplication import UsesQApplication
 
 
-class Dummy(QObject):
-    """Dummy class used in this test."""
+TEST_LIST = ["item1", "item2", "item3"]
+
+
+class Sender(QObject):
+    """Sender class used in this test."""
+
+    foo = Signal()
+    foo_int = Signal(int)
+    dummy = Signal(str)
+    dummy2 = Signal(str, list)
+
     def __init__(self, parent=None):
-        QObject.__init__(self, parent)
+        super().__init__(parent)
 
     def callDummy(self):
-        self.emit(SIGNAL("dummy(PyObject)"), "PyObject")
+        self.dummy.emit("PyObject")
 
     def callDummy2(self):
-        lst = []
-        lst.append("item1")
-        lst.append("item2")
-        lst.append("item3")
-        self.emit(SIGNAL("dummy2(PyObject, PyObject)"), "PyObject0", lst)
+        self.dummy2.emit("PyObject0", TEST_LIST)
 
 
 class PyObjectType(UsesQApplication):
@@ -46,35 +46,33 @@ class PyObjectType(UsesQApplication):
 
     def mySlot2(self, arg0, arg1):
         self.assertEqual(arg0, "PyObject0")
-        self.assertEqual(arg1[0], "item1")
-        self.assertEqual(arg1[1], "item2")
-        self.assertEqual(arg1[2], "item3")
+        self.assertEqual(arg1, TEST_LIST)
         self.callCount += 1
         if self.running:
             self.app.quit()
 
     def setUp(self):
-        super(PyObjectType, self).setUp()
+        super().setUp()
         self.callCount = 0
         self.running = False
 
     def testWithOneArg(self):
-        o = Dummy()
-        o.connect(SIGNAL("dummy(PyObject)"), self.mySlot)
+        o = Sender()
+        o.dummy.connect(self.mySlot)
         o.callDummy()
         self.assertEqual(self.callCount, 1)
 
     def testWithTwoArg(self):
-        o = Dummy()
-        o.connect(SIGNAL("dummy2(PyObject,PyObject)"), self.mySlot2)
+        o = Sender()
+        o.dummy2.connect(self.mySlot2)
         o.callDummy2()
         self.assertEqual(self.callCount, 1)
 
     def testAsyncSignal(self):
         self.called = False
         self.running = True
-        o = Dummy()
-        o.connect(SIGNAL("dummy2(PyObject,PyObject)"), self.mySlot2, Qt.QueuedConnection)
+        o = Sender()
+        o.dummy2.connect(self.mySlot2, Qt.QueuedConnection)
         o.callDummy2()
         self.app.exec()
         self.assertEqual(self.callCount, 1)
@@ -82,8 +80,8 @@ class PyObjectType(UsesQApplication):
     def testTwice(self):
         self.called = False
         self.running = True
-        o = Dummy()
-        o.connect(SIGNAL("dummy2(PyObject,PyObject)"), self.mySlot2, Qt.QueuedConnection)
+        o = Sender()
+        o.dummy2.connect(self.mySlot2, Qt.QueuedConnection)
         o.callDummy2()
         o.callDummy2()
         self.app.exec()
@@ -97,7 +95,7 @@ class PythonSigSlot(unittest.TestCase):
     def tearDown(self):
         try:
             del self.args
-        except:
+        except:  # noqa: E722
             pass
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
@@ -108,98 +106,98 @@ class PythonSigSlot(unittest.TestCase):
 
     def testNoArgs(self):
         """Python signal and slots without arguments"""
-        obj1 = Dummy()
+        obj1 = Sender()
 
-        QObject.connect(obj1, SIGNAL('foo()'), self.callback)
+        obj1.foo.connect(self.callback)
         self.args = tuple()
-        obj1.emit(SIGNAL('foo()'), *self.args)
+        obj1.foo.emit(*self.args)
 
         self.assertTrue(self.called)
 
     def testWithArgs(self):
         """Python signal and slots with integer arguments"""
-        obj1 = Dummy()
+        obj1 = Sender()
 
-        QObject.connect(obj1, SIGNAL('foo(int)'), self.callback)
+        obj1.foo_int.connect(self.callback)
         self.args = (42,)
-        obj1.emit(SIGNAL('foo(int)'), *self.args)
+        obj1.foo_int.emit(*self.args)
 
         self.assertTrue(self.called)
 
     def testDisconnect(self):
-        obj1 = Dummy()
+        obj1 = Sender()
 
-        QObject.connect(obj1, SIGNAL('foo(int)'), self.callback)
-        QObject.disconnect(obj1, SIGNAL('foo(int)'), self.callback)
+        obj1.foo_int.connect(self.callback)
+        self.assertTrue(obj1.foo_int.disconnect(self.callback))
 
         self.args = (42, )
-        obj1.emit(SIGNAL('foo(int)'), *self.args)
+        obj1.foo_int.emit(*self.args)
 
         self.assertTrue(not self.called)
 
 
-if hasQtGui:
-    class SpinBoxPySignal(UsesQApplication):
-        """Tests the connection of python signals to QSpinBox qt slots."""
+class SpinBoxPySignal(UsesQApplication):
+    """Tests the connection of python signals to QSpinBox qt slots."""
 
-        def setUp(self):
-            super(SpinBoxPySignal, self).setUp()
-            self.obj = Dummy()
-            self.spin = QSpinBox()
-            self.spin.setValue(0)
+    def setUp(self):
+        super().setUp()
+        self.obj = Sender()
+        self.spin = QSpinBox()
+        self.spin.setValue(0)
 
-        def tearDown(self):
-            super(SpinBoxPySignal, self).tearDown()
-            del self.obj
-            del self.spin
-            # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
-            gc.collect()
+    def tearDown(self):
+        super().tearDown()
+        del self.obj
+        del self.spin
+        # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+        gc.collect()
+
+    def testValueChanged(self):
+        """Emission of a python signal to QSpinBox setValue(int)"""
 
-        def testValueChanged(self):
-            """Emission of a python signal to QSpinBox setValue(int)"""
-            QObject.connect(self.obj, SIGNAL('dummy(int)'), self.spin, SLOT('setValue(int)'))
-            self.assertEqual(self.spin.value(), 0)
+        self.obj.foo_int.connect(self.spin.setValue)
+        self.assertEqual(self.spin.value(), 0)
 
-            self.obj.emit(SIGNAL('dummy(int)'), 4)
-            self.assertEqual(self.spin.value(), 4)
+        self.obj.foo_int.emit(4)
+        self.assertEqual(self.spin.value(), 4)
 
-        def testValueChangedMultiple(self):
-            """Multiple emissions of a python signal to QSpinBox setValue(int)"""
-            QObject.connect(self.obj, SIGNAL('dummy(int)'), self.spin, SLOT('setValue(int)'))
-            self.assertEqual(self.spin.value(), 0)
+    def testValueChangedMultiple(self):
+        """Multiple emissions of a python signal to QSpinBox setValue(int)"""
+        self.obj.foo_int.connect(self.spin.setValue)
+        self.assertEqual(self.spin.value(), 0)
 
-            self.obj.emit(SIGNAL('dummy(int)'), 4)
-            self.assertEqual(self.spin.value(), 4)
+        self.obj.foo_int.emit(4)
+        self.assertEqual(self.spin.value(), 4)
 
-            self.obj.emit(SIGNAL('dummy(int)'), 77)
-            self.assertEqual(self.spin.value(), 77)
+        self.obj.foo_int.emit(77)
+        self.assertEqual(self.spin.value(), 77)
 
 
-if hasQtGui:
-    class WidgetPySignal(UsesQApplication):
-        """Tests the connection of python signals to QWidget qt slots."""
+class WidgetPySignal(UsesQApplication):
+    """Tests the connection of python signals to QWidget qt slots."""
+
+    def setUp(self):
+        super(WidgetPySignal, self).setUp()
+        self.obj = Sender()
+        self.widget = QWidget()
 
-        def setUp(self):
-            super(WidgetPySignal, self).setUp()
-            self.obj = Dummy()
-            self.widget = QWidget()
+    def tearDown(self):
+        super(WidgetPySignal, self).tearDown()
+        del self.obj
+        del self.widget
+        # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+        gc.collect()
 
-        def tearDown(self):
-            super(WidgetPySignal, self).tearDown()
-            del self.obj
-            del self.widget
-            # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
-            gc.collect()
+    def testShow(self):
+        """Emission of a python signal to QWidget slot show()"""
+        self.widget.hide()
 
-        def testShow(self):
-            """Emission of a python signal to QWidget slot show()"""
-            self.widget.hide()
+        self.obj.foo.connect(self.widget.show)
+        self.assertTrue(not self.widget.isVisible())
 
-            QObject.connect(self.obj, SIGNAL('dummy()'), self.widget, SLOT('show()'))
-            self.assertTrue(not self.widget.isVisible())
+        self.obj.foo.emit()
+        self.assertTrue(self.widget.isVisible())
 
-            self.obj.emit(SIGNAL('dummy()'))
-            self.assertTrue(self.widget.isVisible())
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/sources/pyside6/tests/signals/qobject_callable_connect_test.py b/sources/pyside6/tests/signals/qobject_callable_connect_test.py
new file mode 100644 (file)
index 0000000..a7a26d6
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from PySide6.QtCore import QObject, Signal
+
+
+class Emitter(QObject):
+    sig = Signal(int)
+
+
+class CallableObject(QObject):
+    called = False
+    x = 0
+
+    def __call__(self, x: int):
+        self.called = True
+        self.x = x
+
+
+class QObjectCallableConnectTest(unittest.TestCase):
+    '''Test case for QObject.connect() when the callable is also a QObject.'''
+
+    def testCallableConnect(self):
+        emitter = Emitter()
+        obj = CallableObject()
+        x = 1
+
+        emitter.sig.connect(obj)
+        emitter.sig.emit(x)
+
+        self.assertTrue(obj.called)
+        self.assertEqual(obj.x, x)
+
+
+if __name__ == '__main__':
+    unittest.main()
index 08807e78e0cc5207536d6bb47329cd59b5a93459..a21762b41da2d430fb97ad422fa8c000dc73d64a 100644 (file)
@@ -11,7 +11,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL
+from PySide6.QtCore import QObject
 
 
 class QObjectDestroyed(unittest.TestCase):
index 485584ec2fe4c18583a948d362878ef13db9dff0..9c1121eb871293fbe52c1a92174f629228747d9f 100644 (file)
@@ -13,7 +13,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QCoreApplication, QObject, QTimer, SIGNAL
+from PySide6.QtCore import QCoreApplication, QObject, QTimer, Signal
 from helper.usesqapplication import UsesQApplication
 
 
@@ -22,6 +22,10 @@ class ExtQTimer(QTimer):
         super().__init__()
 
 
+class Sender(QObject):
+    foo = Signal()
+
+
 class Receiver(QObject):
     def __init__(self):
         super().__init__()
@@ -37,10 +41,10 @@ class ObjectSenderTest(unittest.TestCase):
     '''Test case for QObject.sender() method.'''
 
     def testSenderPythonSignal(self):
-        sender = QObject()
+        sender = Sender()
         recv = Receiver()
-        QObject.connect(sender, SIGNAL('foo()'), recv.callback)
-        sender.emit(SIGNAL('foo()'))
+        sender.foo.connect(recv.callback)
+        sender.foo.emit()
         self.assertEqual(sender, recv.the_sender)
 
 
@@ -48,10 +52,10 @@ class ObjectSenderCheckOnReceiverTest(unittest.TestCase):
     '''Test case for QObject.sender() method, this one tests the equality on the Receiver object.'''
 
     def testSenderPythonSignal(self):
-        sender = QObject()
+        sender = Sender()
         recv = Receiver()
-        QObject.connect(sender, SIGNAL('foo()'), recv.callback)
-        sender.emit(SIGNAL('foo()'))
+        sender.foo.connect(recv.callback)
+        sender.foo.emit()
         self.assertEqual(sender, recv.the_sender)
 
 
index a830b55ddafdee569d169e218773418ead5bad10..1a62b2218baf565f80c1b6f7b243def667619241 100644 (file)
@@ -37,5 +37,3 @@ class BoundAndUnboundSignalsTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
-
index e0d71cff57752a8244dacb5cb347742c37da99ec..54b6f4a52fa6dd3142b19fee4219d49ab835577f 100644 (file)
@@ -12,7 +12,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QCoreApplication, QTimeLine
+from PySide6.QtCore import QTimeLine
 from helper.usesqapplication import UsesQApplication
 
 
@@ -58,4 +58,3 @@ class NativeSignalsTest(UsesQApplication):
 
 if __name__ == '__main__':
     unittest.main()
-
index 2df2d7cef4c5512a2b4f87fdca18d0330e57846d..c43c2e549f2fff65a53d20f8b6d1d64390ebe688 100644 (file)
@@ -40,4 +40,3 @@ class DisconnectSignalsTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index b478aff2a2a8d97350519b419dbd15e7110e3b00..fce8014569f93cd93e6288e19c8852b768c56f5f 100644 (file)
@@ -53,17 +53,6 @@ class UserSignalTest(unittest.TestCase):
         self.emitter.mySignal.emit()
         self.assertEqual(self.counter, 2)
 
-#    def testConnectWithConfigureMethod(self):
-#
-#        def slot():
-#            self.counter += 1
-#
-#        self.emitter.pyqtConfigure(mySignal=slot)
-#        self.assertEqual(self.counter, 0)
-#        self.emitter.mySignal.emit()
-#        self.assertEqual(self.counter, 1)
-
 
 if __name__ == '__main__':
     unittest.main()
-
index b6c5b4a1057d1c2916d92c84e89e5baa4e95b7dd..fb9debf39d3901a68da9855f4b63b177b1a7050e 100644 (file)
@@ -12,7 +12,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, QCoreApplication, QTimeLine, Slot
+from PySide6.QtCore import QObject, QTimeLine, Slot
 from helper.usesqapplication import UsesQApplication
 
 
@@ -56,4 +56,3 @@ class UserSlotTest(UsesQApplication):
 
 if __name__ == '__main__':
     unittest.main()
-
index 21fbe545c33123839f70c76556d7c88173559f61..a827131dba3fafb59d85c3acf4b1d334bd5469da 100644 (file)
@@ -12,7 +12,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, QCoreApplication, QTimeLine, Signal, Slot
+from PySide6.QtCore import QObject, QTimeLine, Signal, Slot
 from helper.usesqapplication import UsesQApplication
 
 
@@ -59,4 +59,3 @@ class SignaltoSignalTest(UsesQApplication):
 
 if __name__ == '__main__':
     unittest.main()
-
index c85ab10c0d8ad5eeca7e6606ba05e4925dfd1fe5..cb0df0978d1c0cde1d535e45512675949141fe9a 100644 (file)
@@ -11,7 +11,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL
+from PySide6.QtCore import QObject, Signal
 
 # Description of the problem
 # After creating an PyObject that inherits from QObject, connecting it,
@@ -20,16 +20,19 @@ from PySide6.QtCore import QObject, SIGNAL
 
 # Somehow the underlying QObject also points to the same position.
 
-# In PyQt4, the connection works fine with the same memory behavior,
-# so it looks like specific to SIP.
 
+class Sender(QObject):
+
+    bar = Signal(int)
 
-class Dummy(QObject):
     def __init__(self, parent=None):
         QObject.__init__(self, parent)
 
 
 class Joe(QObject):
+
+    bar = Signal(int)
+
     def __init__(self, parent=None):
         QObject.__init__(self, parent)
 
@@ -44,7 +47,7 @@ class SegfaultCase(unittest.TestCase):
     def tearDown(self):
         try:
             del self.args
-        except:
+        except:  # noqa: E722
             pass
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
@@ -55,22 +58,21 @@ class SegfaultCase(unittest.TestCase):
 
     def testSegfault(self):
         """Regression: Segfault for qobjects in the same memory position."""
-        obj = Dummy()
-        QObject.connect(obj, SIGNAL('bar(int)'), self.callback)
+        obj = Sender()
+        obj.bar.connect(self.callback)
         self.args = (33,)
-        obj.emit(SIGNAL('bar(int)'), self.args[0])
+        obj.bar.emit(self.args[0])
         self.assertTrue(self.called)
         del obj
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
 
         obj = Joe()
-        QObject.connect(obj, SIGNAL('bar(int)'), self.callback)
+        obj.bar.connect(self.callback)
         self.args = (33,)
-        obj.emit(SIGNAL('bar(int)'), self.args[0])
+        obj.bar.emit(self.args[0])
         self.assertTrue(self.called)
 
 
 if __name__ == '__main__':
     unittest.main()
-
index d6c03db18a6c4f90cbd230d00b1d73c7656e0406..08ca725f8b3ac925c34acea53a75f5389193b254 100644 (file)
@@ -13,17 +13,27 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, SLOT
+from PySide6.QtCore import QObject, Slot
 from PySide6.QtWidgets import QPushButton, QWidget
 
 from helper.usesqapplication import UsesQApplication
 
 
+class Receiver(QObject):
+    def __init__(self, p=None):
+        super().__init__(p)
+        self.triggered = False
+
+    @Slot(bool, int)
+    def default_parameter_slot(self, bool_value, int_value=0):
+        self.triggered = True
+
+
 class SelfConnect(UsesQApplication):
 
     def testButtonClickClose(self):
         button = QPushButton()
-        button.connect(button, SIGNAL('clicked()'), SLOT('close()'))
+        button.clicked.connect(button.close)
 
         button.show()
         self.assertTrue(button.isVisible())
@@ -33,13 +43,22 @@ class SelfConnect(UsesQApplication):
     def testWindowButtonClickClose(self):
         button = QPushButton()
         window = QWidget()
-        window.connect(button, SIGNAL('clicked()'), SLOT('close()'))
+        button.clicked.connect(window.close)
 
         window.show()
         self.assertTrue(window.isVisible())
         button.click()
         self.assertTrue(not window.isVisible())
 
+    def testDefaultParameters(self):
+        button = QPushButton()
+        receiver = Receiver(button)
+        button.clicked.connect(receiver.default_parameter_slot)
+        button.clicked.connect(button.close)
+        button.show()
+        button.click()
+        self.assertTrue(receiver.triggered)
+
 
 if __name__ == '__main__':
     unittest.main()
index 434518336bd320901a8a34dc38ebdfd6b2d890db..1ad4bc24c1f5a013735b98a77088b98b96e44311 100644 (file)
@@ -11,11 +11,17 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, SLOT
+from PySide6.QtCore import QObject, Signal
 
 
-class Dummy(QObject):
-    """Dummy class used in this test."""
+class Sender(QObject):
+    """Sender class used in this test."""
+
+    foo = Signal()
+    foo_int = Signal(int)
+    foo_int_int_string = Signal(int, int, str)
+    foo_int_qobject = Signal(int, QObject)
+
     def __init__(self, parent=None):
         QObject.__init__(self, parent)
 
@@ -27,7 +33,7 @@ class ShortCircuitSignals(unittest.TestCase):
     def tearDown(self):
         try:
             del self.args
-        except:
+        except:  # noqa: E722
             pass
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
@@ -38,40 +44,40 @@ class ShortCircuitSignals(unittest.TestCase):
 
     def testNoArgs(self):
         """Short circuit signal without arguments"""
-        obj1 = Dummy()
-        QObject.connect(obj1, SIGNAL('foo()'), self.callback)
+        obj1 = Sender()
+        obj1.foo.connect(self.callback)
         self.args = tuple()
-        obj1.emit(SIGNAL('foo()'), *self.args)
+        obj1.foo.emit(*self.args)
         self.assertTrue(self.called)
 
     def testWithArgs(self):
         """Short circuit signal with integer arguments"""
-        obj1 = Dummy()
+        obj1 = Sender()
 
-        QObject.connect(obj1, SIGNAL('foo(int)'), self.callback)
+        obj1.foo_int.connect(self.callback)
         self.args = (42,)
-        obj1.emit(SIGNAL('foo(int)'), *self.args)
+        obj1.foo_int.emit(*self.args)
 
         self.assertTrue(self.called)
 
     def testMultipleArgs(self):
         """Short circuit signal with multiple arguments"""
-        obj1 = Dummy()
+        obj1 = Sender()
 
-        QObject.connect(obj1, SIGNAL('foo(int,int,QString)'), self.callback)
+        obj1.foo_int_int_string.connect(self.callback)
         self.args = (42, 33, 'char')
-        obj1.emit(SIGNAL('foo(int,int,QString)'), *self.args)
+        obj1.foo_int_int_string.emit(*self.args)
 
         self.assertTrue(self.called)
 
     def testComplexArgs(self):
         """Short circuit signal with complex arguments"""
-        obj1 = Dummy()
+        obj1 = Sender()
 
-        QObject.connect(obj1, SIGNAL('foo(int,QObject*)'), self.callback)
+        obj1.foo_int_qobject.connect(self.callback)
         self.args = (42, obj1)
-        obj1.emit(SIGNAL('foo(int,QObject*)'), *self.args)
 
+        obj1.foo_int_qobject.emit(*self.args)
         self.assertTrue(self.called)
 
 
index c755a9dca9ef0a340c27d9def5d0eae0ca01eaee..31129f7a14e493ecdc4d7eec78d3f29f7d06149a 100644 (file)
@@ -13,7 +13,20 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL
+from PySide6.QtCore import QObject, Signal
+
+
+class Sender(QObject):
+
+    mysignal_int = Signal(int)
+    mysignal_int_int = Signal(int, int)
+    mysignal_string = Signal(str)
+
+
+class Forwarder(Sender):
+
+    forward = Signal()
+    forward_qobject = Signal(QObject)
 
 
 def cute_slot():
@@ -25,8 +38,8 @@ class TestSignal2SignalConnect(unittest.TestCase):
 
     def setUp(self):
         # Set up the basic resources needed
-        self.sender = QObject()
-        self.forwarder = QObject()
+        self.sender = Sender()
+        self.forwarder = Forwarder()
         self.args = None
         self.called = False
 
@@ -34,11 +47,11 @@ class TestSignal2SignalConnect(unittest.TestCase):
         # Delete used resources
         try:
             del self.sender
-        except:
+        except:  # noqa: E722
             pass
         try:
             del self.forwarder
-        except:
+        except:  # noqa: E722
             pass
         del self.args
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
@@ -63,47 +76,37 @@ class TestSignal2SignalConnect(unittest.TestCase):
             raise TypeError("Invalid arguments")
 
     def testSignalWithoutArguments(self):
-        QObject.connect(self.sender, SIGNAL("destroyed()"),
-                        self.forwarder, SIGNAL("forward()"))
-        QObject.connect(self.forwarder, SIGNAL("forward()"),
-                        self.callback_noargs)
+        self.sender.destroyed.connect(self.forwarder.forward)
+        self.forwarder.forward.connect(self.callback_noargs)
         del self.sender
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
         self.assertTrue(self.called)
 
     def testSignalWithOnePrimitiveTypeArgument(self):
-        QObject.connect(self.sender, SIGNAL("mysignal(int)"),
-                        self.forwarder, SIGNAL("mysignal(int)"))
-        QObject.connect(self.forwarder, SIGNAL("mysignal(int)"),
-                        self.callback_args)
+        self.sender.mysignal_int.connect(self.forwarder.mysignal_int)
+        self.forwarder.mysignal_int.connect(self.callback_args)
         self.args = (19,)
-        self.sender.emit(SIGNAL('mysignal(int)'), *self.args)
+        self.sender.mysignal_int.emit(*self.args)
         self.assertTrue(self.called)
 
     def testSignalWithMultiplePrimitiveTypeArguments(self):
-        QObject.connect(self.sender, SIGNAL("mysignal(int,int)"),
-                        self.forwarder, SIGNAL("mysignal(int,int)"))
-        QObject.connect(self.forwarder, SIGNAL("mysignal(int,int)"),
-                        self.callback_args)
+        self.sender.mysignal_int_int.connect(self.forwarder.mysignal_int_int)
+        self.forwarder.mysignal_int_int.connect(self.callback_args)
         self.args = (23, 29)
-        self.sender.emit(SIGNAL('mysignal(int,int)'), *self.args)
+        self.sender.mysignal_int_int.emit(*self.args)
         self.assertTrue(self.called)
 
     def testSignalWithOneStringArgument(self):
-        QObject.connect(self.sender, SIGNAL("mysignal(QString)"),
-                        self.forwarder, SIGNAL("mysignal(QString)"))
-        QObject.connect(self.forwarder, SIGNAL("mysignal(QString)"),
-                        self.callback_args)
+        self.sender.mysignal_string.connect(self.forwarder.mysignal_string)
+        self.forwarder.mysignal_string.connect(self.callback_args)
         self.args = ('myargument',)
-        self.sender.emit(SIGNAL('mysignal(QString)'), *self.args)
+        self.sender.mysignal_string.emit(*self.args)
         self.assertTrue(self.called)
 
     def testSignalWithOneQObjectArgument(self):
-        QObject.connect(self.sender, SIGNAL('destroyed(QObject*)'),
-                        self.forwarder, SIGNAL('forward(QObject*)'))
-        QObject.connect(self.forwarder, SIGNAL('forward(QObject*)'),
-                        self.callback_qobject)
+        self.sender.destroyed.connect(self.forwarder.forward_qobject)
+        self.forwarder.forward_qobject.connect(self.callback_qobject)
 
         obj_name = 'sender'
         self.sender.setObjectName(obj_name)
@@ -116,5 +119,3 @@ class TestSignal2SignalConnect(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
-
index 820a77444eec8fed14085d181fa9ff18b7b8bdd3..51d1cea3abea6acf22aef52b091e26fb65edf178 100644 (file)
@@ -27,7 +27,7 @@ class MyObject(QWidget):
 class AutoConnectionTest(unittest.TestCase):
 
     def testConnection(self):
-        app = QApplication([])
+        app = QApplication([])  # noqa: F841
 
         win = MyObject()
         btn = QPushButton("click", win)
index 95ce1fa4f6969cc84abdaaec184e94b6d00998b2..0a69c1e02f9e96a2d8082247c9c8fbe85c822ba1 100644 (file)
@@ -10,13 +10,16 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, Qt
+from PySide6.QtCore import QObject, Signal, Qt
 
 
-class Dummy(QObject):
+class Sender(QObject):
     """Dummy class used in this test."""
+
+    foo = Signal()
+
     def __init__(self, parent=None):
-        QObject.__init__(self, parent)
+        super().__init__(parent)
 
 
 class TestConnectionTypeSupport(unittest.TestCase):
@@ -26,11 +29,11 @@ class TestConnectionTypeSupport(unittest.TestCase):
 
     def testNoArgs(self):
         """Connect signal using a Qt.ConnectionType as argument"""
-        obj1 = Dummy()
+        obj1 = Sender()
 
-        QObject.connect(obj1, SIGNAL('foo()'), self.callback, Qt.DirectConnection)
+        obj1.foo.connect(self.callback, Qt.DirectConnection)
         self.args = tuple()
-        obj1.emit(SIGNAL('foo()'), *self.args)
+        obj1.foo.emit(*self.args)
 
         self.assertTrue(self.called)
 
index aae96f2366eb403d9677a70fd0a36ddae522fb83..5a49b9d1262ba962b41165589370705abe35a5a9 100644 (file)
@@ -14,112 +14,104 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, SLOT
-
-try:
-    from PySide6.QtWidgets import QSpinBox, QPushButton
-    hasQtGui = True
-except ImportError:
-    hasQtGui = False
+from PySide6.QtWidgets import QSpinBox, QPushButton
 
 from helper.basicpyslotcase import BasicPySlotCase
 from helper.usesqapplication import UsesQApplication
 
-if hasQtGui:
-    class ButtonPySlot(UsesQApplication, BasicPySlotCase):
-        """Tests the connection of python slots to QPushButton signals"""
-
-        def testButtonClicked(self):
-            """Connection of a python slot to QPushButton.clicked()"""
-            button = QPushButton('Mylabel')
-            button.clicked.connect(self.cb)
-            self.args = tuple()
-            button.emit(SIGNAL('clicked(bool)'), False)
-            self.assertTrue(self.called)
-
-        def testButtonClick(self):
-            """Indirect qt signal emission using the QPushButton.click() method """
-            button = QPushButton('label')
-            button.clicked.connect(self.cb)
-            self.args = tuple()
-            button.click()
-            self.assertTrue(self.called)
-
-
-if hasQtGui:
-    class SpinBoxPySlot(UsesQApplication, BasicPySlotCase):
-        """Tests the connection of python slots to QSpinBox signals"""
-
-        def setUp(self):
-            super(SpinBoxPySlot, self).setUp()
-            self.spin = QSpinBox()
-
-        def tearDown(self):
-            del self.spin
-            # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
-            gc.collect()
-            super(SpinBoxPySlot, self).tearDown()
-
-        def testSpinBoxValueChanged(self):
-            """Connection of a python slot to QSpinBox.valueChanged(int)"""
-            self.spin.valueChanged.connect(self.cb)
-            self.args = [3]
-            self.spin.emit(SIGNAL('valueChanged(int)'), *self.args)
-            self.assertTrue(self.called)
-
-        def testSpinBoxValueChangedImplicit(self):
-            """Indirect qt signal emission using QSpinBox.setValue(int)"""
-            self.spin.valueChanged.connect(self.cb)
-            self.args = [42]
-            self.spin.setValue(self.args[0])
-            self.assertTrue(self.called)
-
-        def atestSpinBoxValueChangedFewArgs(self):
-            """Emission of signals with fewer arguments than needed"""
-            # XXX: PyQt4 crashes on the assertRaises
-            self.spin.valueChanged.connect(self.cb)
-            self.args = (554,)
-            self.assertRaises(TypeError, self.spin.emit, SIGNAL('valueChanged(int)'))
-
-if hasQtGui:
-    class QSpinBoxQtSlots(UsesQApplication):
-        """Tests the connection to QSpinBox qt slots"""
-
-        qapplication = True
-
-        def testSetValueIndirect(self):
-            """Indirect signal emission: QSpinBox using valueChanged(int)/setValue(int)"""
-            spinSend = QSpinBox()
-            spinRec = QSpinBox()
-
-            spinRec.setValue(5)
-
-            spinSend.valueChanged.connect(spinRec.setValue)
-            self.assertEqual(spinRec.value(), 5)
-            spinSend.setValue(3)
-            self.assertEqual(spinRec.value(), 3)
-            self.assertEqual(spinSend.value(), 3)
-
-        def testSetValue(self):
-            """Direct signal emission: QSpinBox using valueChanged(int)/setValue(int)"""
-            spinSend = QSpinBox()
-            spinRec = QSpinBox()
-
-            spinRec.setValue(5)
-            spinSend.setValue(42)
-
-            spinSend.valueChanged.connect(spinRec.setValue)
-            self.assertEqual(spinRec.value(), 5)
-            self.assertEqual(spinSend.value(), 42)
-            spinSend.emit(SIGNAL('valueChanged(int)'), 3)
-
-            self.assertEqual(spinRec.value(), 3)
-            # Direct emission shouldn't change the value of the emitter
-            self.assertEqual(spinSend.value(), 42)
-
-            spinSend.emit(SIGNAL('valueChanged(int)'), 66)
-            self.assertEqual(spinRec.value(), 66)
-            self.assertEqual(spinSend.value(), 42)
+
+class ButtonPySlot(UsesQApplication, BasicPySlotCase):
+    """Tests the connection of python slots to QPushButton signals"""
+
+    def testButtonClicked(self):
+        """Connection of a python slot to QPushButton.clicked()"""
+        button = QPushButton('Mylabel')
+        button.clicked.connect(self.cb)
+        self.args = tuple()
+        button.clicked.emit()
+        self.assertTrue(self.called)
+
+    def testButtonClick(self):
+        """Indirect qt signal emission using the QPushButton.click() method """
+        button = QPushButton('label')
+        button.clicked.connect(self.cb)
+        self.args = tuple()
+        button.click()
+        self.assertTrue(self.called)
+
+
+class SpinBoxPySlot(UsesQApplication, BasicPySlotCase):
+    """Tests the connection of python slots to QSpinBox signals"""
+
+    def setUp(self):
+        super(SpinBoxPySlot, self).setUp()
+        self.spin = QSpinBox()
+
+    def tearDown(self):
+        del self.spin
+        # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
+        gc.collect()
+        super(SpinBoxPySlot, self).tearDown()
+
+    def testSpinBoxValueChanged(self):
+        """Connection of a python slot to QSpinBox.valueChanged(int)"""
+        self.spin.valueChanged.connect(self.cb)
+        self.args = [3]
+        self.spin.valueChanged.emit(*self.args)
+        self.assertTrue(self.called)
+
+    def testSpinBoxValueChangedImplicit(self):
+        """Indirect qt signal emission using QSpinBox.setValue(int)"""
+        self.spin.valueChanged.connect(self.cb)
+        self.args = [42]
+        self.spin.setValue(self.args[0])
+        self.assertTrue(self.called)
+
+    def atestSpinBoxValueChangedFewArgs(self):
+        """Emission of signals with fewer arguments than needed"""
+        self.spin.valueChanged.connect(self.cb)
+        self.args = (554,)
+        self.assertRaises(TypeError, self.spin.valueChanged.emit)
+
+
+class QSpinBoxQtSlots(UsesQApplication):
+    """Tests the connection to QSpinBox qt slots"""
+
+    qapplication = True
+
+    def testSetValueIndirect(self):
+        """Indirect signal emission: QSpinBox using valueChanged(int)/setValue(int)"""
+        spinSend = QSpinBox()
+        spinRec = QSpinBox()
+
+        spinRec.setValue(5)
+
+        spinSend.valueChanged.connect(spinRec.setValue)
+        self.assertEqual(spinRec.value(), 5)
+        spinSend.setValue(3)
+        self.assertEqual(spinRec.value(), 3)
+        self.assertEqual(spinSend.value(), 3)
+
+    def testSetValue(self):
+        """Direct signal emission: QSpinBox using valueChanged(int)/setValue(int)"""
+        spinSend = QSpinBox()
+        spinRec = QSpinBox()
+
+        spinRec.setValue(5)
+        spinSend.setValue(42)
+
+        spinSend.valueChanged.connect(spinRec.setValue)
+        self.assertEqual(spinRec.value(), 5)
+        self.assertEqual(spinSend.value(), 42)
+        spinSend.valueChanged.emit(3)
+
+        self.assertEqual(spinRec.value(), 3)
+        # Direct emission shouldn't change the value of the emitter
+        self.assertEqual(spinSend.value(), 42)
+
+        spinSend.valueChanged.emit(66)
+        self.assertEqual(spinRec.value(), 66)
+        self.assertEqual(spinSend.value(), 42)
 
 
 if __name__ == '__main__':
index 1439432e967b94cd1e37ba37fdfa21eeb9d6814a..b31d89c2fce3d6b6380b5aad52b76e07c57de027 100644 (file)
@@ -14,9 +14,8 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, SLOT, QProcess, QTimeLine
+from PySide6.QtCore import QObject, Signal, SIGNAL, QProcess, QTimeLine
 
-from helper.basicpyslotcase import BasicPySlotCase
 from helper.usesqapplication import UsesQApplication
 
 
@@ -26,7 +25,7 @@ class ArgsOnEmptySignal(UsesQApplication):
     def testArgsToNoArgsSignal(self):
         '''Passing arguments to a signal without arguments'''
         process = QProcess()
-        self.assertRaises(TypeError, process.emit, SIGNAL('started()'), 42)
+        self.assertRaises(TypeError, process.started.emit, 42)
 
 
 class MoreArgsOnEmit(UsesQApplication):
@@ -35,12 +34,14 @@ class MoreArgsOnEmit(UsesQApplication):
     def testMoreArgs(self):
         '''Passing more arguments than needed'''
         process = QProcess()
-        self.assertRaises(TypeError, process.emit, SIGNAL('finished(int)'), 55, 55)
+        self.assertRaises(TypeError, process.finished.emit, 55, QProcess.ExitStatus.NormalExit, 42)
 
 
-class Dummy(QObject):
-    '''Dummy class'''
-    pass
+class Sender(QObject):
+    '''Sender class'''
+
+    dummy = Signal()
+    dummy_int = Signal(int)
 
 
 class PythonSignalToCppSlots(UsesQApplication):
@@ -49,12 +50,11 @@ class PythonSignalToCppSlots(UsesQApplication):
     def testWithoutArgs(self):
         '''Connect python signal to QTimeLine.toggleDirection()'''
         timeline = QTimeLine()
-        dummy = Dummy()
-        QObject.connect(dummy, SIGNAL('dummy()'),
-                        timeline, SLOT('toggleDirection()'))
+        sender = Sender()
+        sender.dummy.connect(timeline.toggleDirection)
 
         orig_dir = timeline.direction()
-        dummy.emit(SIGNAL('dummy()'))
+        sender.dummy.emit()
         new_dir = timeline.direction()
 
         if orig_dir == QTimeLine.Forward:
@@ -65,13 +65,12 @@ class PythonSignalToCppSlots(UsesQApplication):
     def testWithArgs(self):
         '''Connect python signals to QTimeLine.setCurrentTime(int)'''
         timeline = QTimeLine()
-        dummy = Dummy()
+        sender = Sender()
 
-        QObject.connect(dummy, SIGNAL('dummy(int)'),
-                        timeline, SLOT('setCurrentTime(int)'))
+        sender.dummy_int.connect(timeline.setCurrentTime)
 
         current = timeline.currentTime()
-        dummy.emit(SIGNAL('dummy(int)'), current + 42)
+        sender.dummy_int.emit(current + 42)
         self.assertEqual(timeline.currentTime(), current + 42)
 
 
@@ -83,13 +82,13 @@ class CppSignalsToCppSlots(UsesQApplication):
         process = QProcess()
         timeline = QTimeLine()
 
-        QObject.connect(process, SIGNAL('finished(int, QProcess::ExitStatus)'),
-                        timeline, SLOT('toggleDirection()'))
+        process.finished.connect(timeline.toggleDirection)
 
         orig_dir = timeline.direction()
 
         process.start(sys.executable, ['-c', '"print 42"'])
-        process.waitForFinished()
+        self.assertTrue(process.waitForStarted())
+        self.assertTrue(process.waitForFinished())
 
         new_dir = timeline.direction()
 
@@ -112,9 +111,9 @@ class DynamicSignalsToFuncPartial(UsesQApplication):
     def testIt(self):
         global called
         called = False
-        o = QObject()
-        o.connect(o, SIGNAL("ASignal()"), functools.partial(someSlot, "partial .."))
-        o.emit(SIGNAL("ASignal()"))
+        o = Sender()
+        o.dummy.connect(functools.partial(someSlot, "partial .."))
+        o.dummy.emit()
         self.assertTrue(called)
 
 
index 31d3bc85ef805d0b0831877e9154fdf4052d1225..955d5b65b2c9fdc0b72ac806edcd0583dcf8dfa6 100644 (file)
@@ -12,11 +12,12 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL
+from PySide6.QtCore import QObject
 
 
 class SignalManagerRefCount(unittest.TestCase):
-    """Simple test case to check if the signal_manager is erroneously incrementing the object refcounter"""
+    """Simple test case to check if the signal_manager is erroneously incrementing the
+       object refcounter."""
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testObjectRefcount(self):
@@ -27,10 +28,9 @@ class SignalManagerRefCount(unittest.TestCase):
         refcount = sys.getrefcount(obj)
         obj.destroyed.connect(callback)
         self.assertEqual(refcount, sys.getrefcount(obj))
-        QObject.disconnect(obj, SIGNAL('destroyed()'), callback)
+        obj.destroyed.disconnect(callback)
         self.assertEqual(refcount, sys.getrefcount(obj))
 
 
 if __name__ == '__main__':
     unittest.main()
-
index 59bc1b29f7be48021e59071deea86cf90fc6c2d8..e8f08b2d9fb6b7f4cccd8c0a404bdbcb8112f1ef 100644 (file)
@@ -20,6 +20,10 @@ called = False
 name = "Old"
 
 
+class Sender(QObject):
+    dummySignal = Signal()
+
+
 class Obj(QObject):
     dummySignalArgs = Signal(str)
     numberSignal = Signal(int)
@@ -78,9 +82,9 @@ class TestConnectNotifyWithNewStyleSignals(UsesQApplication):
 
     def testStaticSlot(self):
         global called
-        sender = Obj()
-        sender.connect(sender, SIGNAL("dummySignal()"), Obj.static_method)
-        sender.emit(SIGNAL("dummySignal()"))
+        sender = Sender()
+        sender.dummySignal.connect(Obj.static_method)
+        sender.dummySignal.emit()
         self.assertTrue(called)
 
     def testStaticSlotArgs(self):
@@ -99,4 +103,3 @@ class TestConnectNotifyWithNewStyleSignals(UsesQApplication):
 
 if __name__ == '__main__':
     unittest.main()
-
index a4d5f33a778608dc94d54a06da49cb17acd12cb8..01492b333a94773f30ce391e6c84bfc176fc1dd3 100644 (file)
@@ -10,7 +10,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QCoreApplication, QObject, QTimeLine, SIGNAL
+from PySide6.QtCore import QCoreApplication, QTimeLine
 
 
 class SignalPrimitiveTypeTest(unittest.TestCase):
@@ -36,5 +36,3 @@ class SignalPrimitiveTypeTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
-
diff --git a/sources/pyside6/tests/signals/signals.pyproject b/sources/pyside6/tests/signals/signals.pyproject
new file mode 100644 (file)
index 0000000..b63724e
--- /dev/null
@@ -0,0 +1,19 @@
+{
+    "files": ["anonymous_slot_leak_test.py", "args_dont_match_test.py",
+              "bug_189.py", "bug_311.py", "bug_312.py", "bug_319.py", "bug_79.py",
+              "decorators_test.py", "disconnect_test.py", "invalid_callback_test.py",
+              "lambda_gui_test.py", "lambda_test.py", "leaking_signal_test.py",
+              "multiple_connections_gui_test.py", "multiple_connections_test.py",
+              "pysignal_test.py", "qobject_callable_connect_test.py", "qobject_destroyed_test.py",
+              "qobject_receivers_test.py", "qobject_sender_test.py", "ref01_test.py",
+              "ref02_test.py", "ref03_test.py", "ref04_test.py", "ref05_test.py",
+              "ref06_test.py", "segfault_proxyparent_test.py",
+              "self_connect_test.py", "short_circuit_test.py",
+              "signal2signal_connect_test.py", "signal_across_threads.py",
+              "signal_autoconnect_test.py", "signal_connectiontype_support_test.py",
+              "signal_emission_gui_test.py", "signal_emission_test.py",
+              "signal_enum_test.py", "signal_func_test.py", "signal_manager_refcount_test.py",
+              "signal_newenum_test.py", "signal_number_limit_test.py",
+              "signal_object_test.py", "signal_signature_test.py", "signal_with_primitive_type_test.py",
+              "slot_reference_count_test.py", "static_metaobject_test.py"]
+}
index 10a40597e06abcd2bc7dc58244f89cbc8458f918..9d5c7365205bf4f0d8f1ef13f1a50a60b6f318a7 100644 (file)
@@ -12,12 +12,14 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, SLOT
+from PySide6.QtCore import QObject, Signal
 
 
 class Dummy(QObject):
+    foo = Signal()
+
     def dispatch(self):
-        self.emit(SIGNAL('foo()'))
+        self.foo.emit()
 
 
 class PythonSignalRefCount(unittest.TestCase):
@@ -35,10 +37,10 @@ class PythonSignalRefCount(unittest.TestCase):
 
         self.assertEqual(sys.getrefcount(cb), 2)
 
-        QObject.connect(self.emitter, SIGNAL('foo()'), cb)
+        self.emitter.foo.connect(cb)
         self.assertEqual(sys.getrefcount(cb), 3)
 
-        QObject.disconnect(self.emitter, SIGNAL('foo()'), cb)
+        self.emitter.foo.disconnect(cb)
         self.assertEqual(sys.getrefcount(cb), 2)
 
 
@@ -60,7 +62,7 @@ class CppSignalRefCount(unittest.TestCase):
         self.emitter.destroyed.connect(cb)
         self.assertEqual(sys.getrefcount(cb), 3)
 
-        QObject.disconnect(self.emitter, SIGNAL('destroyed()'), cb)
+        self.emitter.destroyed.disconnect(cb)
         self.assertEqual(sys.getrefcount(cb), 2)
 
 
index 6b1372d5468de984787873d91869a37a2f9a245d..d7bf73e44e24fb9275e74708fa3e33baa75d5be5 100644 (file)
@@ -14,13 +14,22 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from init_paths import init_test_paths
 init_test_paths(False)
 
-from PySide6.QtCore import QObject, SIGNAL, Slot
+from PySide6.QtCore import QObject, Signal, Slot, SIGNAL
 from helper.usesqapplication import UsesQApplication
 
 
+class Sender(QObject):
+
+    foo = Signal()
+    foo2 = Signal()
+
+
 class MyObject(QObject):
+
+    foo2 = Signal()
+
     def __init__(self, parent=None):
-        QObject.__init__(self, parent)
+        super().__init__(parent)
         self._slotCalledCount = 0
 
     # this '@Slot()' is needed to get the right sort order in testSharedSignalEmission.
@@ -33,7 +42,8 @@ class MyObject(QObject):
 class StaticMetaObjectTest(UsesQApplication):
 
     def testSignalPropagation(self):
-        o = MyObject()
+        """Old style, dynamic signal creation."""
+        o = QObject()
         o2 = MyObject()
 
         # SIGNAL foo not created yet
@@ -55,17 +65,17 @@ class StaticMetaObjectTest(UsesQApplication):
         self.assertEqual(o.metaObject().indexOfSignal("foo()"), -1)
 
     def testSharedSignalEmission(self):
-        o = QObject()
+        o = Sender()
         m = MyObject()
 
-        o.connect(SIGNAL("foo2()"), m.mySlot)
-        m.connect(SIGNAL("foo2()"), m.mySlot)
-        o.emit(SIGNAL("foo2()"))
+        o.foo2.connect(m.mySlot)
+        m.foo2.connect(m.mySlot)
+        o.foo2.emit()
         self.assertEqual(m._slotCalledCount, 1)
         del o
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
-        m.emit(SIGNAL("foo2()"))
+        m.foo2.emit()
         self.assertEqual(m._slotCalledCount, 2)
 
 
index 81c2c9a4ae02c00e5a1253f230c68faef9e0d484..ec575e923b24673bbc4a906feaeb51aef8999d1e 100644 (file)
@@ -14,7 +14,7 @@ from unittest import mock
 from unittest.mock import patch
 
 sys.path.append(os.fspath(Path(__file__).resolve().parents[2]))
-from init_paths import init_test_paths
+from init_paths import init_test_paths  # noqa: E402
 init_test_paths(False)
 
 
@@ -75,17 +75,29 @@ class TestPySide6AndroidDeployWidgets(DeployTestBase):
         self.config_file = self.temp_example / "pysidedeploy.spec"
         self.buildozer_config = self.temp_example / "buildozer.spec"
 
-    def test_dry_run(self, mock_extract_jar):
+    @patch("deploy_lib.android.android_config.AndroidConfig._find_local_libs")
+    @patch("deploy_lib.android.android_config.AndroidConfig._find_dependent_qt_modules")
+    @patch("deploy_lib.android.android_config.find_qtlibs_in_wheel")
+    def test_dry_run(self, mock_qtlibs, mock_extraqtmodules, mock_local_libs, mock_extract_jar):
+        mock_qtlibs.return_value = self.pyside_wheel / "PySide6/Qt/lib"
+        mock_extraqtmodules.return_value = []
+        dependent_plugins = ["platforms_qtforandroid",
+                             "platforminputcontexts_qtvirtualkeyboardplugin",
+                             "iconengines_qsvgicon"]
+        mock_local_libs.return_value = [], dependent_plugins
         self.android_deploy.main(name="android_app", shiboken_wheel=self.shiboken_wheel,
                                  pyside_wheel=self.pyside_wheel, ndk_path=self.ndk_path,
                                  dry_run=True, force=True)
+
         self.assertEqual(mock_extract_jar.call_count, 0)
+        self.assertEqual(mock_qtlibs.call_count, 1)
+        self.assertEqual(mock_extraqtmodules.call_count, 1)
+        self.assertEqual(mock_local_libs.call_count, 1)
 
     @patch("deploy_lib.android.buildozer.BuildozerConfig._BuildozerConfig__find_jars")
     @patch("deploy_lib.android.android_config.AndroidConfig.recipes_exist")
-    @patch("deploy_lib.android.buildozer.BuildozerConfig."
-           "_BuildozerConfig__find_dependent_qt_modules")
-    @patch("deploy_lib.android.buildozer.find_qtlibs_in_wheel")
+    @patch("deploy_lib.android.android_config.AndroidConfig._find_dependent_qt_modules")
+    @patch("deploy_lib.android.android_config.find_qtlibs_in_wheel")
     def test_config(self, mock_qtlibs, mock_extraqtmodules, mock_recipes_exist, mock_find_jars,
                     mock_extract_jar):
         jar_dir = "tmp/jar/PySide6/jar"
@@ -126,9 +138,9 @@ class TestPySide6AndroidDeployWidgets(DeployTestBase):
         self.assertIn(str(self.ndk_path), config_obj.get_value("buildozer", "ndk_path"))
         self.assertEqual(config_obj.get_value("buildozer", "sdk_path"), '')
         expected_modules = {"Core", "Gui"}
-        obtained_modules = set(config_obj.get_value("buildozer", "modules").split(","))
+        obtained_modules = set(config_obj.get_value("qt", "modules").split(","))
         self.assertEqual(obtained_modules, expected_modules)
-        expected_local_libs = "plugins_platforms_qtforandroid"
+        expected_local_libs = ""
         self.assertEqual(config_obj.get_value("buildozer", "local_libs"),
                          expected_local_libs)
         self.assertEqual(config_obj.get_value("buildozer", "arch"), "x86_64")
@@ -189,12 +201,11 @@ class TestPySide6AndroidDeployQml(DeployTestBase):
         (self.temp_qml_example / "stringlistmodel.py").rename(self.temp_qml_example / "main.py")
         (self.temp_qml_example / "stringlistmodel.pyproject").unlink()
 
-    @patch("deploy_lib.android.buildozer.BuildozerConfig._BuildozerConfig__find_local_libs")
+    @patch("deploy_lib.android.android_config.AndroidConfig._find_local_libs")
     @patch("deploy_lib.android.buildozer.BuildozerConfig._BuildozerConfig__find_jars")
     @patch("deploy_lib.android.android_config.AndroidConfig.recipes_exist")
-    @patch("deploy_lib.android.buildozer.BuildozerConfig."
-           "_BuildozerConfig__find_dependent_qt_modules")
-    @patch("deploy_lib.android.buildozer.find_qtlibs_in_wheel")
+    @patch("deploy_lib.android.android_config.AndroidConfig._find_dependent_qt_modules")
+    @patch("deploy_lib.android.android_config.find_qtlibs_in_wheel")
     def test_config_with_Qml(self, mock_qtlibs, mock_extraqtmodules, mock_recipes_exist,
                              mock_find_jars, mock_local_libs, mock_extract_jar,
                              mock_qmlimportscanner):
@@ -228,12 +239,11 @@ class TestPySide6AndroidDeployQml(DeployTestBase):
         self.assertTrue(self.config_file.exists())
         self.assertTrue(self.buildozer_config_file.exists())
 
-        # test config file contents
         config_obj = self.deploy_lib.BaseConfig(config_file=self.config_file)
         expected_modules = {"Quick", "Core", "Gui", "Network", "Qml", "QmlModels", "OpenGL"}
-        obtained_modules = set(config_obj.get_value("buildozer", "modules").split(","))
+        obtained_modules = set(config_obj.get_value("qt", "modules").split(","))
         self.assertEqual(obtained_modules, expected_modules)
-        expected_local_libs = "plugins_platforms_qtforandroid"
+        expected_local_libs = ""
         self.assertEqual(config_obj.get_value("buildozer", "local_libs"),
                          expected_local_libs)
         expected_qt_plugins = set(dependent_plugins)
index 9c743674613a6d84aa96077bec0760aa2e65e0f1..f84eec1eb7e535bf722e2f0914ece48fda29f522 100644 (file)
@@ -7,10 +7,15 @@ import shutil
 import sys
 import os
 import importlib
+import platform
 from pathlib import Path
 from unittest.mock import patch
 from unittest import mock
 
+sys.path.append(os.fspath(Path(__file__).resolve().parents[2]))
+from init_paths import init_test_paths, _get_qt_lib_dir  # noqa: E402
+init_test_paths(False)
+
 
 def is_pyenv_python():
     pyenv_root = os.environ.get("PYENV_ROOT")
@@ -58,6 +63,9 @@ class DeployTestBase(LongSortedOptionTest):
         cls.deploy_lib = importlib.import_module("deploy_lib")
         cls.deploy = importlib.import_module("deploy")
         sys.modules["deploy"] = cls.deploy
+        files_to_ignore = [".cpp.o", ".qsb", ".webp"]
+        cls.dlls_ignore_nuitka = " ".join([f"--noinclude-dlls=*{file}"
+                                           for file in files_to_ignore])
 
         # required for comparing long strings
         cls.maxDiff = None
@@ -74,6 +82,9 @@ class DeployTestBase(LongSortedOptionTest):
         os.chdir(self.current_dir)
 
 
+@unittest.skipIf(sys.platform == "darwin" and int(platform.mac_ver()[0].split('.')[0]) <= 11,
+                 "Test only works on macOS version 12+")
+@patch("deploy_lib.config.QtDependencyReader.find_plugin_dependencies")
 class TestPySide6DeployWidgets(DeployTestBase):
     @classmethod
     def setUpClass(cls):
@@ -87,32 +98,45 @@ class TestPySide6DeployWidgets(DeployTestBase):
         os.chdir(self.temp_example_widgets)
         self.main_file = self.temp_example_widgets / "tetrix.py"
         self.deployment_files = self.temp_example_widgets / "deployment"
+        # All the plugins included. This is different from plugins_nuitka, because Nuitka bundles
+        # some plugins by default
+        self.all_plugins = ["accessiblebridge", "egldeviceintegrations", "generic", "iconengines",
+                            "imageformats", "platforminputcontexts", "platforms",
+                            "platforms/darwin", "platformthemes", "styles", "xcbglintegrations"]
+        # Plugins that needs to be passed to Nuitka
+        plugins_nuitka = ("accessiblebridge,platforminputcontexts,platforms/darwin")
         self.expected_run_cmd = (
-            f"{sys.executable} -m nuitka {str(self.main_file)} --follow-imports --onefile"
+            f"{sys.executable} -m nuitka {str(self.main_file)} --follow-imports"
             f" --enable-plugin=pyside6 --output-dir={str(self.deployment_files)} --quiet"
             f" --noinclude-qt-translations"
+            f" --include-qt-plugins={plugins_nuitka}"
+            f" {self.dlls_ignore_nuitka}"
         )
         if sys.platform.startswith("linux"):
-            self.expected_run_cmd += f" --linux-icon={str(self.linux_icon)}"
+            self.expected_run_cmd += f" --linux-icon={str(self.linux_icon)} --onefile"
         elif sys.platform == "darwin":
-            self.expected_run_cmd += f" --macos-app-icon={str(self.macos_icon)}"
+            self.expected_run_cmd += (f" --macos-app-icon={str(self.macos_icon)}"
+                                      " --macos-create-app-bundle --standalone")
         elif sys.platform == "win32":
-            self.expected_run_cmd += f" --windows-icon-from-ico={str(self.win_icon)}"
+            self.expected_run_cmd += f" --windows-icon-from-ico={str(self.win_icon)} --onefile"
 
         if is_pyenv_python():
             self.expected_run_cmd += " --static-libpython=no"
         self.config_file = self.temp_example_widgets / "pysidedeploy.spec"
 
-    def testWidgetDryRun(self):
+    def testWidgetDryRun(self, mock_plugins):
+        mock_plugins.return_value = self.all_plugins
         # Checking for dry run commands is equivalent to mocking the
         # subprocess.check_call() in commands.py as the the dry run command
         # is the command being run.
         original_output = self.deploy.main(self.main_file, dry_run=True, force=True)
         self.assertEqual(original_output, self.expected_run_cmd)
 
-    def testWidgetConfigFile(self):
+    @patch("deploy_lib.dependency_util.QtDependencyReader.get_qt_libs_dir")
+    def testWidgetConfigFile(self, mock_sitepackages, mock_plugins):
+        mock_sitepackages.return_value = Path(_get_qt_lib_dir())
+        mock_plugins.return_value = self.all_plugins
         # includes both dry run and config_file tests
-
         # init
         init_result = self.deploy.main(self.main_file, init=True, force=True)
         self.assertEqual(init_result, None)
@@ -127,15 +151,23 @@ class TestPySide6DeployWidgets(DeployTestBase):
         self.assertEqual(config_obj.get_value("app", "project_dir"), ".")
         self.assertEqual(config_obj.get_value("app", "exec_directory"), ".")
         self.assertEqual(config_obj.get_value("python", "packages"),
-                         "nuitka==1.8.0,ordered_set,zstandard")
+                         "Nuitka==2.3.2")
         self.assertEqual(config_obj.get_value("qt", "qml_files"), "")
         equ_base = "--quiet --noinclude-qt-translations"
         equ_value = equ_base + " --static-libpython=no" if is_pyenv_python() else equ_base
         self.assertEqual(config_obj.get_value("nuitka", "extra_args"), equ_value)
         self.assertEqual(config_obj.get_value("qt", "excluded_qml_plugins"), "")
+        expected_modules = {"Core", "Gui", "Widgets"}
+        if sys.platform != "win32":
+            expected_modules.add("DBus")
+        obtained_modules = set(config_obj.get_value("qt", "modules").split(","))
+        self.assertEqual(obtained_modules, expected_modules)
+        obtained_qt_plugins = config_obj.get_value("qt", "plugins").split(",")
+        self.assertEqual(obtained_qt_plugins.sort(), self.all_plugins.sort())
         self.config_file.unlink()
 
-    def testErrorReturns(self):
+    def testErrorReturns(self, mock_plugins):
+        mock_plugins.return_value = self.all_plugins
         # main file and config file does not exists
         fake_main_file = self.main_file.parent / "main.py"
         with self.assertRaises(RuntimeError) as context:
@@ -143,6 +175,9 @@ class TestPySide6DeployWidgets(DeployTestBase):
         self.assertTrue("Directory does not contain main.py file." in str(context.exception))
 
 
+@unittest.skipIf(sys.platform == "darwin" and int(platform.mac_ver()[0].split('.')[0]) <= 11,
+                 "Test only works on macOS version 12+")
+@patch("deploy_lib.config.QtDependencyReader.find_plugin_dependencies")
 class TestPySide6DeployQml(DeployTestBase):
     @classmethod
     def setUpClass(cls):
@@ -158,13 +193,27 @@ class TestPySide6DeployQml(DeployTestBase):
         self.deployment_files = self.temp_example_qml / "deployment"
         self.first_qml_file = "main.qml"
         self.second_qml_file = "MovingRectangle.qml"
+
+        # All the plugins included. This is different from plugins_nuitka, because Nuitka bundles
+        # some plugins by default
+        self.all_plugins = ["accessiblebridge", "egldeviceintegrations", "generic", "iconengines",
+                            "imageformats", "networkaccess", "networkinformation",
+                            "platforminputcontexts", "platforms", "platforms/darwin",
+                            "platformthemes", "qmltooling", "scenegraph", "tls",
+                            "xcbglintegrations"]
+        # Plugins that needs to be passed to Nuitka
+        plugins_nuitka = ("accessiblebridge,networkaccess,networkinformation,platforminputcontexts,"
+                          "platforms/darwin,qml,qmltooling,scenegraph")
         self.expected_run_cmd = (
-            f"{sys.executable} -m nuitka {str(self.main_file)} --follow-imports --onefile"
+            f"{sys.executable} -m nuitka {str(self.main_file)} --follow-imports"
             f" --enable-plugin=pyside6 --output-dir={str(self.deployment_files)} --quiet"
-            f" --noinclude-qt-translations --include-qt-plugins=all"
+            f" --noinclude-qt-translations"
+            f" {self.dlls_ignore_nuitka}"
+            " --noinclude-dlls=*/qml/QtQuickEffectMaker/*"
+            f" --include-qt-plugins={plugins_nuitka}"
             f" --include-data-files={str(self.temp_example_qml / self.first_qml_file)}="
             f"./main.qml --include-data-files="
-            f"{str(self.temp_example_qml /self.second_qml_file)}=./MovingRectangle.qml"
+            f"{str(self.temp_example_qml / self.second_qml_file)}=./MovingRectangle.qml"
         )
 
         if sys.platform != "win32":
@@ -181,17 +230,21 @@ class TestPySide6DeployQml(DeployTestBase):
             )
 
         if sys.platform.startswith("linux"):
-            self.expected_run_cmd += f" --linux-icon={str(self.linux_icon)}"
+            self.expected_run_cmd += f" --linux-icon={str(self.linux_icon)} --onefile"
         elif sys.platform == "darwin":
-            self.expected_run_cmd += f" --macos-app-icon={str(self.macos_icon)}"
+            self.expected_run_cmd += (f" --macos-app-icon={str(self.macos_icon)}"
+                                      " --macos-create-app-bundle --standalone")
         elif sys.platform == "win32":
-            self.expected_run_cmd += f" --windows-icon-from-ico={str(self.win_icon)}"
+            self.expected_run_cmd += f" --windows-icon-from-ico={str(self.win_icon)} --onefile"
 
         if is_pyenv_python():
             self.expected_run_cmd += " --static-libpython=no"
         self.config_file = self.temp_example_qml / "pysidedeploy.spec"
 
-    def testQmlConfigFile(self):
+    @patch("deploy_lib.dependency_util.QtDependencyReader.get_qt_libs_dir")
+    def testQmlConfigFile(self, mock_sitepackages, mock_plugins):
+        mock_sitepackages.return_value = Path(_get_qt_lib_dir())
+        mock_plugins.return_value = self.all_plugins
         # create config file
         with patch("deploy_lib.config.run_qmlimportscanner") as mock_qmlimportscanner:
             mock_qmlimportscanner.return_value = ["QtQuick"]
@@ -204,7 +257,7 @@ class TestPySide6DeployQml(DeployTestBase):
         self.assertEqual(config_obj.get_value("app", "project_dir"), ".")
         self.assertEqual(config_obj.get_value("app", "exec_directory"), ".")
         self.assertEqual(config_obj.get_value("python", "packages"),
-                         "nuitka==1.8.0,ordered_set,zstandard")
+                         "Nuitka==2.3.2")
         self.assertEqual(config_obj.get_value("qt", "qml_files"), "main.qml,MovingRectangle.qml")
         equ_base = "--quiet --noinclude-qt-translations"
         equ_value = equ_base + " --static-libpython=no" if is_pyenv_python() else equ_base
@@ -213,16 +266,25 @@ class TestPySide6DeployQml(DeployTestBase):
             config_obj.get_value("qt", "excluded_qml_plugins"),
             "QtCharts,QtQuick3D,QtSensors,QtTest,QtWebEngine",
         )
+        expected_modules = {"Core", "Gui", "Qml", "Quick", "Network", "OpenGL", "QmlModels"}
+        if sys.platform != "win32":
+            expected_modules.add("DBus")
+        obtained_modules = set(config_obj.get_value("qt", "modules").split(","))
+        self.assertEqual(obtained_modules, expected_modules)
+        obtained_qt_plugins = config_obj.get_value("qt", "plugins").split(",")
+        self.assertEqual(obtained_qt_plugins.sort(), self.all_plugins.sort())
         self.config_file.unlink()
 
-    def testQmlDryRun(self):
+    def testQmlDryRun(self, mock_plugins):
+        mock_plugins.return_value = self.all_plugins
         with patch("deploy_lib.config.run_qmlimportscanner") as mock_qmlimportscanner:
             mock_qmlimportscanner.return_value = ["QtQuick"]
             original_output = self.deploy.main(self.main_file, dry_run=True, force=True)
             self.assertEqual(original_output, self.expected_run_cmd)
             self.assertEqual(mock_qmlimportscanner.call_count, 1)
 
-    def testMainFileDryRun(self):
+    def testMainFileDryRun(self, mock_plugins):
+        mock_plugins.return_value = self.all_plugins
         with patch("deploy_lib.config.run_qmlimportscanner") as mock_qmlimportscanner:
             mock_qmlimportscanner.return_value = ["QtQuick"]
             original_output = self.deploy.main(Path.cwd() / "main.py", dry_run=True, force=True)
@@ -230,6 +292,8 @@ class TestPySide6DeployQml(DeployTestBase):
             self.assertEqual(mock_qmlimportscanner.call_count, 1)
 
 
+@unittest.skipIf(sys.platform == "darwin" and int(platform.mac_ver()[0].split('.')[0]) <= 11,
+                 "Test only works on macOS version 12+")
 class TestPySide6DeployWebEngine(DeployTestBase):
     @classmethod
     def setUpClass(cls):
@@ -239,12 +303,24 @@ class TestPySide6DeployWebEngine(DeployTestBase):
             shutil.copytree(example_webenginequick, Path(cls.temp_dir) / "nanobrowser")
         ).resolve()
 
-    # this test case retains the QtWebEngine dlls
-    def testWebEngineQuickDryRun(self):
+    @patch("deploy_lib.config.QtDependencyReader.find_plugin_dependencies")
+    @patch("deploy_lib.dependency_util.QtDependencyReader.get_qt_libs_dir")
+    def testWebEngineQuickDryRun(self, mock_sitepackages, mock_plugins):
+        mock_sitepackages.return_value = Path(_get_qt_lib_dir())
+        all_plugins = ["accessiblebridge", "egldeviceintegrations", "generic", "iconengines",
+                       "imageformats", "networkaccess", "networkinformation",
+                       "platforminputcontexts", "platforms", "platforms/darwin",
+                       "platformthemes", "qmltooling", "scenegraph", "tls",
+                       "xcbglintegrations"]
+        mock_plugins.return_value = all_plugins
+        # this test case retains the QtWebEngine dlls
         # setup
         os.chdir(self.temp_example_webenginequick)
         main_file = self.temp_example_webenginequick / "quicknanobrowser.py"
         deployment_files = self.temp_example_webenginequick / "deployment"
+        # Plugins that needs to be passed to Nuitka
+        plugins_nuitka = ("accessiblebridge,networkaccess,networkinformation,platforminputcontexts,"
+                          "platforms/darwin,qml,qmltooling,scenegraph")
         qml_files = [
             "ApplicationRoot.qml",
             "BrowserDialog.qml",
@@ -255,15 +331,18 @@ class TestPySide6DeployWebEngine(DeployTestBase):
         ]
         data_files_cmd = " ".join(
             [
-                f"--include-data-files={str(self.temp_example_webenginequick/file)}=./{file}"
+                f"--include-data-files={str(self.temp_example_webenginequick / file)}=./{file}"
                 for file in qml_files
             ]
         )
         expected_run_cmd = (
-            f"{sys.executable} -m nuitka {str(main_file)} --follow-imports --onefile"
+            f"{sys.executable} -m nuitka {str(main_file)} --follow-imports"
             f" --enable-plugin=pyside6 --output-dir={str(deployment_files)} --quiet"
             f" --noinclude-qt-translations --include-qt-plugins=all"
             f" {data_files_cmd}"
+            f" --include-qt-plugins={plugins_nuitka}"
+            f" {self.dlls_ignore_nuitka}"
+            " --noinclude-dlls=*/qml/QtQuickEffectMaker/*"
         )
 
         if sys.platform != "win32":
@@ -280,11 +359,12 @@ class TestPySide6DeployWebEngine(DeployTestBase):
             )
 
         if sys.platform.startswith("linux"):
-            expected_run_cmd += f" --linux-icon={str(self.linux_icon)}"
+            expected_run_cmd += f" --linux-icon={str(self.linux_icon)} --onefile"
         elif sys.platform == "darwin":
-            expected_run_cmd += f" --macos-app-icon={str(self.macos_icon)}"
+            expected_run_cmd += (f" --macos-app-icon={str(self.macos_icon)}"
+                                 " --macos-create-app-bundle --standalone")
         elif sys.platform == "win32":
-            expected_run_cmd += f" --windows-icon-from-ico={str(self.win_icon)}"
+            expected_run_cmd += f" --windows-icon-from-ico={str(self.win_icon)} --onefile"
 
         config_file = self.temp_example_webenginequick / "pysidedeploy.spec"
 
@@ -307,6 +387,13 @@ class TestPySide6DeployWebEngine(DeployTestBase):
             config_obj.get_value("qt", "excluded_qml_plugins"),
             "QtCharts,QtQuick3D,QtSensors,QtTest",
         )
+        expected_modules = {"Core", "Gui", "Quick", "Qml", "WebEngineQuick", "Network", "OpenGL",
+                            "Positioning", "WebEngineCore", "WebChannel", "WebChannelQuick",
+                            "QmlModels"}
+        if sys.platform != "win32":
+            expected_modules.add("DBus")
+        obtained_modules = set(config_obj.get_value("qt", "modules").split(","))
+        self.assertEqual(obtained_modules, expected_modules)
 
 
 if __name__ == "__main__":
index 836ed30568d095a5ef217f58060a1a806d0e4914..7a532df213f67620458ef6bf184284509405a51b 100644 (file)
@@ -1,5 +1,5 @@
 set(shiboken_MAJOR_VERSION "6")
-set(shiboken_MINOR_VERSION "6")
+set(shiboken_MINOR_VERSION "7")
 set(shiboken_MICRO_VERSION "2")
 set(shiboken_PRE_RELEASE_VERSION_TYPE "")
 set(shiboken_PRE_RELEASE_VERSION "")
index f80be6debf23955f193ba594e41e7f487cc23c01..7aa2fbd11b467dbcda55ae9c27ef19e707813b06 100644 (file)
@@ -18,6 +18,7 @@ abstractmetafunction.cpp abstractmetafunction.h
 abstractmetalang.cpp abstractmetalang.h abstractmetalang_helpers.h abstractmetalang_typedefs.h
 abstractmetatype.cpp abstractmetatype.h
 addedfunction.cpp addedfunction.h addedfunction_p.h
+anystringview_helpers.cpp anystringview_helpers.h
 apiextractor.cpp apiextractor.h apiextractorflags.h
 apiextractorresult.cpp apiextractorresult.h
 arraytypeentry.h
index e922f8d5f04fce3e2ce6c39902f64a21f9eec12b..0720fca7eb97926fc3c642a8c434f2ad58c05c7b 100644 (file)
@@ -161,6 +161,11 @@ const QHash<TypeEntryCPtr, AbstractMetaEnum> &AbstractMetaBuilder::typeEntryToEn
     return d->m_enums;
 }
 
+const QMultiHash<QString, QString> &AbstractMetaBuilder::typedefTargetToName() const
+{
+    return d->m_typedefTargetToName;
+}
+
 void AbstractMetaBuilderPrivate::checkFunctionModifications() const
 {
     const auto &entries = TypeDatabase::instance()->entries();
@@ -245,7 +250,7 @@ void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &f
 
 void AbstractMetaBuilderPrivate::registerToStringCapabilityIn(const NamespaceModelItem &nsItem)
 {
-    const FunctionList &streamOps = nsItem->findFunctions(u"operator<<"_s);
+    const FunctionList &streamOps = nsItem->findFunctions("operator<<");
     for (const FunctionModelItem &item : streamOps)
         registerToStringCapability(item, nullptr);
     for (const NamespaceModelItem &ni : nsItem->namespaces())
@@ -381,7 +386,6 @@ bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem
 
     streamFunction->setArguments(arguments);
 
-    *streamFunction += AbstractMetaFunction::FinalInTargetLang;
     streamFunction->setAccess(Access::Public);
 
     AbstractMetaClassPtr funcClass;
@@ -422,8 +426,8 @@ void AbstractMetaBuilderPrivate::sortLists()
     // this is a temporary solution before new type revision implementation
     // We need move QMetaObject register before QObject.
     Dependencies additionalDependencies;
-    if (auto qObjectClass = AbstractMetaClass::findClass(m_metaClasses, u"QObject")) {
-        if (auto qMetaObjectClass = AbstractMetaClass::findClass(m_metaClasses, u"QMetaObject")) {
+    if (auto qObjectClass = AbstractMetaClass::findClass(m_metaClasses, "QObject")) {
+        if (auto qMetaObjectClass = AbstractMetaClass::findClass(m_metaClasses, "QMetaObject")) {
             Dependency dependency;
             dependency.parent = qMetaObjectClass;
             dependency.child = qObjectClass;
@@ -649,7 +653,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom,
     }
 
     {
-        const FunctionList &hashFunctions = dom->findFunctions(u"qHash"_s);
+        const FunctionList &hashFunctions = dom->findFunctions("qHash");
         for (const FunctionModelItem &item : hashFunctions)
             registerHashFunction(item, nullptr);
     }
@@ -963,9 +967,31 @@ std::optional<AbstractMetaEnum>
     return metaEnum;
 }
 
-AbstractMetaClassPtr AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &,
-                                                               const TypeDefModelItem &typeDef,
-                                                               const AbstractMetaClassPtr &currentClass)
+AbstractMetaClassPtr
+    AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &dom,
+                                                const TypeDefModelItem &typeDef,
+                                                const AbstractMetaClassPtr &currentClass)
+{
+    auto result = traverseTypeDefHelper(dom, typeDef, currentClass);
+    if (!result && typeDef->type().isPlain()) {
+        const auto &type = typeDef->type();
+        QString fullName;
+        if (currentClass)
+            fullName += currentClass->qualifiedCppName() + "::"_L1;
+        fullName += typeDef->name();
+        QString targetName = typeDef->type().toString();
+        m_typedefTargetToName.insert(targetName, fullName);
+        const QByteArray normalized = QMetaObject::normalizedType(targetName.toUtf8().constData());
+        if (targetName != QLatin1StringView(normalized))
+            m_typedefTargetToName.insert(QString::fromUtf8(normalized), fullName);
+    }
+    return result;
+}
+
+AbstractMetaClassPtr
+    AbstractMetaBuilderPrivate::traverseTypeDefHelper(const FileModelItem &,
+                                                      const TypeDefModelItem &typeDef,
+                                                      const AbstractMetaClassPtr &currentClass)
 {
     TypeDatabase *types = TypeDatabase::instance();
     QString className = stripTemplateArgs(typeDef->name());
@@ -1234,7 +1260,7 @@ void AbstractMetaBuilderPrivate::traverseNamespaceMembers(const NamespaceModelIt
 
 static inline QString fieldSignatureWithType(const VariableModelItem &field)
 {
-    return field->name() + QStringLiteral(" -> ") + field->type().toString();
+    return field->name() + " -> "_L1 + field->type().toString();
 }
 
 static inline QString qualifiedFieldSignatureWithType(const QString &className,
@@ -1328,7 +1354,7 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF
         return;
 
     TypeDatabase *types = TypeDatabase::instance();
-    static const QRegularExpression operatorRegExp(QStringLiteral("^operator "));
+    static const QRegularExpression operatorRegExp("^operator "_L1);
     Q_ASSERT(operatorRegExp.isValid());
     QString castTo = metaFunction->name().remove(operatorRegExp).trimmed();
 
@@ -1384,7 +1410,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(const ScopeModelItem& scopeIt
 
     for (AbstractMetaFunction *metaFunction : functions) {
         if (metaClass->isNamespace())
-            *metaFunction += AbstractMetaFunction::Static;
+            metaFunction->setCppAttribute(FunctionAttribute::Static);
 
         const auto propertyFunction = metaClass->searchPropertyFunction(metaFunction->name());
         if (propertyFunction.index >= 0) {
@@ -1425,18 +1451,12 @@ void AbstractMetaBuilderPrivate::traverseFunctions(const ScopeModelItem& scopeIt
             }
         }
 
-        const bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate();
-        const bool isInvalidConstructor = metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction
-            && metaFunction->isPrivate();
-        if (isInvalidConstructor)
+        if (metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction
+            && metaFunction->isPrivate()) {
             metaClass->setHasPrivateConstructor(true);
-        if ((isInvalidDestructor || isInvalidConstructor)
-            && !metaClass->hasNonPrivateConstructor()) {
-            *metaClass += AbstractMetaClass::FinalInTargetLang;
-        } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) {
-            *metaClass -= AbstractMetaClass::FinalInTargetLang;
-            metaClass->setHasNonPrivateConstructor(true);
         }
+        if (metaFunction->isConstructor() && !metaFunction->isPrivate()) // Including Copy CT
+            metaClass->setHasNonPrivateConstructor(true);
 
         if (!metaFunction->isDestructor()
             && !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) {
@@ -1527,22 +1547,13 @@ void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction
             func->setOriginalName(func->name());
             func->setName(mod.renamedToName());
         } else if (mod.isAccessModifier()) {
-            funcRef -= AbstractMetaFunction::Friendly;
-
             if (mod.isPublic())
                 funcRef.modifyAccess(Access::Public);
             else if (mod.isProtected())
                 funcRef.modifyAccess(Access::Protected);
             else if (mod.isPrivate())
                 funcRef.modifyAccess(Access::Private);
-            else if (mod.isFriendly())
-                funcRef += AbstractMetaFunction::Friendly;
         }
-
-        if (mod.isFinal())
-            funcRef += AbstractMetaFunction::FinalInTargetLang;
-        else if (mod.isNonFinal())
-            funcRef -= AbstractMetaFunction::FinalInTargetLang;
     }
 }
 
@@ -1563,7 +1574,8 @@ bool AbstractMetaBuilderPrivate::setupInheritance(const AbstractMetaClassPtr &me
                                              &info, &baseContainerType);
         if (templ) {
             setupInheritance(templ);
-            inheritTemplate(metaClass, templ, info);
+            if (!inheritTemplate(metaClass, templ, info))
+                return false;
             metaClass->typeEntry()->setBaseContainerType(templ->typeEntry());
             return true;
         }
@@ -1580,9 +1592,9 @@ bool AbstractMetaBuilderPrivate::setupInheritance(const AbstractMetaClassPtr &me
             return true;
         }
 
-        qCWarning(lcShiboken).noquote().nospace()
-            << QStringLiteral("template baseclass '%1' of '%2' is not known")
-                              .arg(baseClasses.constFirst(), metaClass->name());
+        qCWarning(lcShiboken, "template baseclass '%s' of '%s' is not known",
+                  qPrintable(baseClasses.constFirst()),
+                  qPrintable(metaClass->name()));
         return false;
     }
 
@@ -1770,7 +1782,7 @@ bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunction
 
     const AbstractMetaArgumentList fargs = metaFunction->arguments();
     if (metaClass->isNamespace())
-        *metaFunction += AbstractMetaFunction::Static;
+        metaFunction->setCppAttribute(FunctionAttribute::Static);
     if (metaFunction->name() == metaClass->name()) {
         metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction);
         if (fargs.size() == 1) {
@@ -2035,7 +2047,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
     if (functionItem->isFriend())
         return nullptr;
 
-    const bool deprecated = functionItem->isDeprecated();
+    const auto cppAttributes = functionItem->attributes();
+    const bool deprecated = cppAttributes.testFlag(FunctionAttribute::Deprecated);
     if (deprecated && m_skipDeprecated) {
         rejectFunction(functionItem, currentClass,
                        AbstractMetaBuilder::GenerationDisabled, u" is deprecated."_s);
@@ -2044,6 +2057,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
 
     AbstractMetaFunction::Flags flags;
     auto *metaFunction = new AbstractMetaFunction(functionName);
+    metaFunction->setCppAttributes(cppAttributes);
     const QByteArray cSignature = signature.toUtf8();
     const QString unresolvedSignature =
         QString::fromUtf8(QMetaObject::normalizedSignature(cSignature.constData()));
@@ -2051,35 +2065,12 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
     if (functionItem->isHiddenFriend())
         flags.setFlag(AbstractMetaFunction::Flag::HiddenFriend);
     metaFunction->setSourceLocation(functionItem->sourceLocation());
-    if (deprecated)
-        *metaFunction += AbstractMetaFunction::Deprecated;
 
     // Additional check for assignment/move assignment down below
     metaFunction->setFunctionType(functionTypeFromCodeModel(functionItem->functionType()));
     metaFunction->setConstant(functionItem->isConstant());
     metaFunction->setExceptionSpecification(functionItem->exceptionSpecification());
 
-    if (functionItem->isAbstract())
-        *metaFunction += AbstractMetaFunction::Abstract;
-
-    if (functionItem->isVirtual()) {
-        *metaFunction += AbstractMetaFunction::VirtualCppMethod;
-        if (functionItem->isOverride())
-            *metaFunction += AbstractMetaFunction::OverriddenCppMethod;
-        if (functionItem->isFinal())
-            *metaFunction += AbstractMetaFunction::FinalCppMethod;
-    } else {
-        *metaFunction += AbstractMetaFunction::FinalInTargetLang;
-    }
-
-    if (functionItem->isInvokable())
-        *metaFunction += AbstractMetaFunction::Invokable;
-
-    if (functionItem->isStatic()) {
-        *metaFunction += AbstractMetaFunction::Static;
-        *metaFunction += AbstractMetaFunction::FinalInTargetLang;
-    }
-
     // Access rights
     metaFunction->setAccess(functionItem->accessPolicy());
 
@@ -2089,7 +2080,6 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
          metaFunction->setType(AbstractMetaType::createVoid());
         break;
     case AbstractMetaFunction::ConstructorFunction:
-        metaFunction->setExplicit(functionItem->isExplicit());
         metaFunction->setName(currentClass->name());
         metaFunction->setType(AbstractMetaType::createVoid());
         break;
@@ -2158,7 +2148,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio
             // If an invalid argument has a default value, simply remove it
             // unless the function is virtual (since the override in the
             // wrapper can then not correctly be generated).
-            if (arg->defaultValue() && !functionItem->isVirtual()) {
+            if (arg->defaultValue()
+                && !functionItem->attributes().testFlag(FunctionAttribute::Virtual)) {
                 if (!currentClass || currentClass->typeEntry()->generateCode()) {
                     const QString signature = qualifiedFunctionSignatureWithType(functionItem, className);
                     qCWarning(lcShiboken, "%s",
@@ -2379,7 +2370,7 @@ TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualif
 AbstractMetaClassCPtr AbstractMetaBuilderPrivate::resolveTypeSystemTypeDef(const AbstractMetaType &t) const
 {
     if (t.hasInstantiations()) {
-        auto pred = [t](const TypeClassEntry &e) { return e.type.equals(t); };
+        auto pred = [t](const TypeClassEntry &e) { return e.type == t; };
         auto it = std::find_if(m_typeSystemTypeDefs.cbegin(), m_typeSystemTypeDefs.cend(), pred);
         if (it != m_typeSystemTypeDefs.cend())
             return it->klass;
@@ -2650,7 +2641,7 @@ std::optional<AbstractMetaType>
     bool isConstCharStarCase =
             oneDimensionalArrayOfUnspecifiedSize
             && typeInfo.qualifiedName().size() == 1
-            && typeInfo.qualifiedName().at(0) == QStringLiteral("char")
+            && typeInfo.qualifiedName().at(0) == "char"_L1
             && typeInfo.indirections() == 0
             && typeInfo.isConstant()
             && typeInfo.referenceType() == NoReference
@@ -2863,7 +2854,7 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV
 
     // This is a very lame way to handle expression evaluation,
     // but it is not critical and will do for the time being.
-    static const QRegularExpression variableNameRegExp(QStringLiteral("^[a-zA-Z_][a-zA-Z0-9_]*$"));
+    static const QRegularExpression variableNameRegExp("^[a-zA-Z_][a-zA-Z0-9_]*$"_L1);
     Q_ASSERT(variableNameRegExp.isValid());
     if (!variableNameRegExp.match(stringValue).hasMatch()) {
         ok = true;
@@ -3138,80 +3129,103 @@ std::optional<AbstractMetaType>
 AbstractMetaClassPtr
     AbstractMetaBuilder::inheritTemplateClass(const ComplexTypeEntryPtr &te,
                                               const AbstractMetaClassCPtr &templateClass,
-                                              const AbstractMetaTypeList &templateTypes,
-                                              InheritTemplateFlags flags)
+                                              const AbstractMetaTypeList &templateTypes)
 {
     auto result = std::make_shared<AbstractMetaClass>();
     result->setTypeDef(true);
 
     result->setTypeEntry(te);
     if (!AbstractMetaBuilderPrivate::inheritTemplate(result, templateClass,
-                                                     templateTypes, flags)) {
+                                                     templateTypes)) {
         return {};
     }
     AbstractMetaBuilderPrivate::inheritTemplateFunctions(result);
     return result;
 }
 
+
+static std::optional<AbstractMetaType>
+    inheritTemplateParameter(const AbstractMetaClassPtr &subclass,
+                             const AbstractMetaClassCPtr &templateClass,
+                             const TypeInfo &info, QString *errorMessage)
+{
+    QString typeName = info.qualifiedName().join("::"_L1);
+    TypeDatabase *typeDb = TypeDatabase::instance();
+    TypeEntryPtr t;
+    // Check for a non-type template integer parameter, that is, for a base
+    // "template <int R, int C> Matrix<R, C>" and subclass
+    // "typedef Matrix<2,3> Matrix2x3;". If so, create dummy entries of
+    // EnumValueTypeEntry for the integer values encountered on the fly.
+    if (isNumber(typeName)) {
+        t = typeDb->findType(typeName);
+        if (!t) {
+            auto parent = typeSystemTypeEntry(subclass->typeEntry());
+            t = TypeDatabase::instance()->addConstantValueTypeEntry(typeName, parent);
+        }
+    } else {
+        QStringList possibleNames;
+        possibleNames << subclass->qualifiedCppName() + "::"_L1 + typeName;
+        possibleNames << templateClass->qualifiedCppName() + "::"_L1 + typeName;
+        if (subclass->enclosingClass())
+            possibleNames << subclass->enclosingClass()->qualifiedCppName() + "::"_L1 + typeName;
+        possibleNames << typeName;
+
+        for (const QString &possibleName : std::as_const(possibleNames)) {
+            t = typeDb->findType(possibleName);
+            if (t)
+                break;
+        }
+    }
+
+    if (!t) {
+        *errorMessage = msgIgnoringTemplateParameter(typeName,
+                            "The corresponding type was not found in the typesystem.");
+        return std::nullopt;
+    }
+
+    if (t->isContainer()) {
+        *errorMessage = msgIgnoringTemplateParameter(typeName,
+                            "Template inheritance from nested containers is not supported");
+        return std::nullopt;
+    }
+    AbstractMetaType result(t);
+    result.setConstant(info.isConstant());
+    result.setReferenceType(info.referenceType());
+    result.setIndirectionsV(info.indirectionsV());
+    result.decideUsagePattern();
+    return result;
+}
+
 bool AbstractMetaBuilderPrivate::inheritTemplate(const AbstractMetaClassPtr &subclass,
                                                  const AbstractMetaClassCPtr &templateClass,
                                                  const TypeInfo &info)
 {
     AbstractMetaTypeList  templateTypes;
 
+    QString errorMessage;
     for (const TypeInfo &i : info.instantiations()) {
-        QString typeName = i.qualifiedName().join(u"::"_s);
-        TypeDatabase *typeDb = TypeDatabase::instance();
-        TypeEntryPtr t;
-        // Check for a non-type template integer parameter, that is, for a base
-        // "template <int R, int C> Matrix<R, C>" and subclass
-        // "typedef Matrix<2,3> Matrix2x3;". If so, create dummy entries of
-        // EnumValueTypeEntry for the integer values encountered on the fly.
-        if (isNumber(typeName)) {
-            t = typeDb->findType(typeName);
-            if (!t) {
-                auto parent = typeSystemTypeEntry(subclass->typeEntry());
-                t = TypeDatabase::instance()->addConstantValueTypeEntry(typeName, parent);
-            }
-        } else {
-            QStringList possibleNames;
-            possibleNames << subclass->qualifiedCppName() + u"::"_s + typeName;
-            possibleNames << templateClass->qualifiedCppName() + u"::"_s + typeName;
-            if (subclass->enclosingClass())
-                possibleNames << subclass->enclosingClass()->qualifiedCppName() + u"::"_s + typeName;
-            possibleNames << typeName;
-
-            for (const QString &possibleName : std::as_const(possibleNames)) {
-                t = typeDb->findType(possibleName);
-                if (t)
-                    break;
-            }
-        }
-
-        if (t) {
-            AbstractMetaType temporaryType(t);
-            temporaryType.setConstant(i.isConstant());
-            temporaryType.setReferenceType(i.referenceType());
-            temporaryType.setIndirectionsV(i.indirectionsV());
-            temporaryType.decideUsagePattern();
-            templateTypes << temporaryType;
+        const auto typeO = inheritTemplateParameter(subclass, templateClass, i, &errorMessage);
+        if (typeO.has_value()) {
+            templateTypes.append(typeO.value());
         } else {
-            qCWarning(lcShiboken).noquote().nospace()
-                << "Ignoring template parameter " << typeName << " from "
-                << info.toString() << ". The corresponding type was not found in the typesystem.";
+            errorMessage = msgInheritTemplateIssue(subclass, info, errorMessage);
+            qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
         }
     }
+    if (templateTypes.isEmpty()) {
+         errorMessage = msgInheritTemplateIssue(subclass, info,
+                                                "No template parameters could be inherited"_L1);
+         qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
+         return false;
+    }
     return inheritTemplate(subclass, templateClass, templateTypes);
 }
 
 bool AbstractMetaBuilderPrivate::inheritTemplate(const AbstractMetaClassPtr &subclass,
                                                  const AbstractMetaClassCPtr &templateClass,
-                                                 const AbstractMetaTypeList &templateTypes,
-                                                 InheritTemplateFlags flags)
+                                                 const AbstractMetaTypeList &templateTypes)
 {
     subclass->setTemplateBaseClass(templateClass);
-    if (flags.testFlag(InheritTemplateFlag::SetEnclosingClass))
-        subclass->setEnclosingClass(templateClass->enclosingClass());
     subclass->setTemplateBaseClassInstantiations(templateTypes);
     subclass->setBaseClass(templateClass->baseClass());
     return true;
@@ -3550,16 +3564,22 @@ static QList<std::shared_ptr<MetaClass> >
     if (!result.isValid() && graph.nodeCount()) {
         QTemporaryFile tempFile(QDir::tempPath() + u"/cyclic_depXXXXXX.dot"_s);
         tempFile.setAutoRemove(false);
-        tempFile.open();
-        graph.dumpDot(tempFile.fileName(),
-                      [] (const AbstractMetaClassCPtr &c) { return c->name(); });
+        const bool ok = tempFile.open();
+        if (ok) {
+            graph.dumpDot(tempFile.fileName(),
+                          [] (const AbstractMetaClassCPtr &c) { return c->name(); });
+        }
 
         QString message;
         QTextStream str(&message);
         str << "Cyclic dependency of classes found:";
         for (const auto &c : result.cyclic)
             str << ' ' << c->name();
-        str << ". Graph can be found at \"" << QDir::toNativeSeparators(tempFile.fileName()) << '"';
+        str << '.';
+        if (ok) {
+            str << " Graph can be found at \""
+                << QDir::toNativeSeparators(tempFile.fileName()) << '"';
+        }
         qCWarning(lcShiboken, "%s", qPrintable(message));
     }
 
index b00a69363125cbecdf590057572b579132d084d1..20261ed3c777ee2e09dda68ad7bb36e90b03f911 100644 (file)
@@ -54,6 +54,7 @@ public:
     const AbstractMetaFunctionCList &globalFunctions() const;
     const AbstractMetaEnumList &globalEnums() const;
     const QHash<TypeEntryCPtr, AbstractMetaEnum> &typeEntryToEnumsHash() const;
+    const QMultiHash<QString, QString> &typedefTargetToName() const;
 
     bool build(const QByteArrayList &arguments,
                ApiExtractorFlags apiExtractorFlags = {},
@@ -99,10 +100,9 @@ public:
                                 const AbstractMetaTypeList &templateTypes);
 
     static AbstractMetaClassPtr
-        inheritTemplateClass(const ComplexTypeEntryPtr &te,
-                             const AbstractMetaClassCPtr &templateClass,
-                             const AbstractMetaTypeList &templateTypes,
-                             InheritTemplateFlags flags = {});
+    inheritTemplateClass(const ComplexTypeEntryPtr &te,
+                         const AbstractMetaClassCPtr &templateClass,
+                         const AbstractMetaTypeList &templateTypes);
 
     /// Performs a template specialization of the member function.
     /// \param function Member function
index 39ade64388ef3acdf0bfc75cbf7b1b685ac06e72..e65a4f176d601e57dbd8bd842cd557667e665769 100644 (file)
@@ -17,6 +17,7 @@
 #include <QtCore/QFileInfo>
 #include <QtCore/QList>
 #include <QtCore/QMap>
+#include <QtCore/QMultiHash>
 #include <QtCore/QSet>
 
 #include <optional>
@@ -77,6 +78,9 @@ public:
     AbstractMetaClassPtr traverseTypeDef(const FileModelItem &dom,
                                        const TypeDefModelItem &typeDef,
                                        const AbstractMetaClassPtr &currentClass);
+    AbstractMetaClassPtr traverseTypeDefHelper(const FileModelItem &dom,
+                                               const TypeDefModelItem &typeDef,
+                                               const AbstractMetaClassPtr &currentClass);
     void traverseTypesystemTypedefs();
     AbstractMetaClassPtr traverseClass(const FileModelItem &dom,
                                      const ClassModelItem &item,
@@ -186,8 +190,7 @@ public:
                                 const TypeInfo &info);
     static bool inheritTemplate(const AbstractMetaClassPtr &subclass,
                                 const AbstractMetaClassCPtr &templateClass,
-                                const AbstractMetaTypeList &templateTypes,
-                                InheritTemplateFlags flags = {});
+                                const AbstractMetaTypeList &templateTypes);
 
     static AbstractMetaFunctionPtr
         inheritTemplateFunction(const AbstractMetaFunctionCPtr &function,
@@ -240,6 +243,7 @@ public:
     QFileInfoList m_globalHeaders;
     QStringList m_headerPaths;
     mutable QHash<QString, Include> m_resolveIncludeHash;
+    QMultiHash<QString, QString> m_typedefTargetToName;
     QList<TypeClassEntry> m_typeSystemTypeDefs; // look up metatype->class for type system typedefs
     ApiExtractorFlags m_apiExtractorFlags;
     bool m_skipDeprecated = false;
index 6bcf5ea9adffd5d98fac2619fcacab130e293126..11a02f154f4d4d8b80c55d81be652afd3add0644 100644 (file)
@@ -48,7 +48,6 @@ public:
     AbstractMetaFunctionPrivate()
         : m_constant(false),
           m_reverse(false),
-          m_explicit(false),
           m_pointerOperator(false),
           m_isCallOperator(false)
     {
@@ -87,10 +86,10 @@ public:
     AddedFunctionPtr m_addedFunction;
     SourceLocation m_sourceLocation;
     AbstractMetaFunction::Attributes m_attributes;
+    FunctionAttributes m_cppAttributes;
     AbstractMetaFunction::Flags m_flags;
     uint m_constant                 : 1;
     uint m_reverse                  : 1;
-    uint m_explicit                 : 1;
     uint m_pointerOperator          : 1;
     uint m_isCallOperator           : 1;
     mutable int m_cachedOverloadNumber = TypeSystem::OverloadNumberUnset;
@@ -120,9 +119,9 @@ AbstractMetaFunction::AbstractMetaFunction(const AddedFunctionPtr &addedFunc) :
         setAccess(Access::Public);
         break;
     }
-    AbstractMetaFunction::Attributes atts = AbstractMetaFunction::FinalInTargetLang;
+    AbstractMetaFunction::Attributes atts;
     if (addedFunc->isStatic())
-        atts |= AbstractMetaFunction::Static;
+        setCppAttribute(FunctionAttribute::Static);
     if (addedFunc->isClassMethod())
         atts |= AbstractMetaFunction::ClassMethod;
     setAttributes(atts);
@@ -215,12 +214,12 @@ void AbstractMetaFunction::setPointerOperator(bool value)
 
 bool AbstractMetaFunction::isExplicit() const
 {
-    return d->m_explicit;
+    return d->m_cppAttributes.testFlag(FunctionAttribute::Explicit);
 }
 
 void AbstractMetaFunction::setExplicit(bool isExplicit)
 {
-    d->m_explicit = isExplicit;
+    d->m_cppAttributes.setFlag(FunctionAttribute::Explicit, isExplicit);
 }
 
 bool AbstractMetaFunction::returnsBool() const
@@ -262,6 +261,21 @@ void AbstractMetaFunction::operator-=(AbstractMetaFunction::Attribute attribute)
     d->m_attributes.setFlag(attribute, false);
 }
 
+FunctionAttributes AbstractMetaFunction::cppAttributes() const
+{
+    return d->m_cppAttributes;
+}
+
+void AbstractMetaFunction::setCppAttributes(FunctionAttributes a)
+{
+    d->m_cppAttributes = a;
+}
+
+void AbstractMetaFunction::setCppAttribute(FunctionAttribute a, bool on)
+{
+    d->m_cppAttributes.setFlag(a, on);
+}
+
 AbstractMetaFunction::Flags AbstractMetaFunction::flags() const
 {
     return d->m_flags;
@@ -342,7 +356,7 @@ AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const Abstra
         result |= EqualImplementor;
 
     // Attributes
-    if (attributes() == other->attributes())
+    if (attributes() == other->attributes() && cppAttributes() == other->cppAttributes())
         result |= EqualAttributes;
 
     // Compare types
@@ -427,6 +441,10 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const
 {
     auto *cpy = new AbstractMetaFunction;
     cpy->setAttributes(attributes());
+    auto ca = cppAttributes();
+    // Historical bug: explicit was not copied! (causing nontypetemplate_test.py fail)
+    ca.setFlag(FunctionAttribute::Explicit, false);
+    cpy->setCppAttributes(ca);
     cpy->setFlags(flags());
     cpy->setAccess(access());
     cpy->setName(name());
@@ -574,6 +592,11 @@ bool AbstractMetaFunction::isUserAdded() const
     return d->m_addedFunction && !d->m_addedFunction->isDeclaration();
 }
 
+bool AbstractMetaFunction::isUserAddedPythonOverride() const
+{
+    return d->m_addedFunction && d->m_addedFunction->isPythonOverride();
+}
+
 bool AbstractMetaFunction::isUserDeclared() const
 {
     return d->m_addedFunction && d->m_addedFunction->isDeclaration();
@@ -729,7 +752,8 @@ static bool modifiedUndeprecated(const FunctionModification &mod)
 bool AbstractMetaFunction::isDeprecated() const
 {
     const auto &mods = modifications(declaringClass());
-    return d->m_attributes.testFlag(Attribute::Deprecated)
+
+    return d->m_cppAttributes.testFlag(FunctionAttribute::Deprecated)
            ? std::none_of(mods.cbegin(), mods.cend(), modifiedUndeprecated)
            : std::any_of(mods.cbegin(), mods.cend(), modifiedDeprecated);
 }
@@ -1020,9 +1044,10 @@ QString AbstractMetaFunction::signatureComment() const
 QString AbstractMetaFunction::debugSignature() const
 {
     QString result;
-    const bool isOverride = attributes() & AbstractMetaFunction::OverriddenCppMethod;
-    const bool isFinal = attributes() & AbstractMetaFunction::FinalCppMethod;
-    if (!isOverride && !isFinal && (attributes() & AbstractMetaFunction::VirtualCppMethod))
+    const auto attributes = cppAttributes();
+    const bool isOverride = attributes.testFlag(FunctionAttribute::Override);
+    const bool isFinal = attributes.testFlag(FunctionAttribute::Final);
+    if (!isOverride && !isFinal && (attributes.testFlag(FunctionAttribute::Virtual)))
         result += u"virtual "_s;
     if (d->m_implementingClass)
         result += d->m_implementingClass->qualifiedCppName() + u"::"_s;
@@ -1120,6 +1145,17 @@ void AbstractMetaFunction::setTypeEntry(const FunctionTypeEntryPtr &typeEntry)
     d->m_typeEntry = typeEntry;
 }
 
+QString AbstractMetaFunction::targetLangPackage() const
+{
+    if (d->m_addedFunction != nullptr)
+        return d->m_addedFunction->targetLangPackage();
+    if (d->m_class != nullptr)
+        return d->m_class->typeEntry()->targetLangPackage();
+    if (d->m_typeEntry != nullptr)
+        return d->m_typeEntry->targetLangPackage();
+    return {};
+}
+
 bool AbstractMetaFunction::isCallOperator() const
 {
     return d->m_name == u"operator()";
@@ -1375,7 +1411,7 @@ bool AbstractMetaFunction::isInplaceOperator() const
 
 bool AbstractMetaFunction::isVirtual() const
 {
-    return d->m_attributes.testFlag(AbstractMetaFunction::VirtualCppMethod);
+    return d->m_cppAttributes.testFlag(FunctionAttribute::Virtual);
 }
 
 QString AbstractMetaFunctionPrivate::modifiedName(const AbstractMetaFunction *q) const
@@ -1400,7 +1436,7 @@ QString AbstractMetaFunction::modifiedName() const
 
 AbstractMetaFunctionCPtr
 AbstractMetaFunction::find(const AbstractMetaFunctionCList &haystack,
-                           QStringView needle)
+                           QAnyStringView needle)
 {
     for (const auto &f : haystack) {
         if (f->name() == needle)
@@ -1519,7 +1555,7 @@ bool AbstractMetaFunction::injectedCodeUsesPySelf() const
 bool AbstractMetaFunction::injectedCodeCallsPythonOverride() const
 {
     static const QRegularExpression
-        overrideCallRegexCheck(QStringLiteral(R"(PyObject_Call\s*\(\s*%PYTHON_METHOD_OVERRIDE\s*,)"));
+        overrideCallRegexCheck(R"(PyObject_Call\s*\(\s*%PYTHON_METHOD_OVERRIDE\s*,)"_L1);
     Q_ASSERT(overrideCallRegexCheck.isValid());
     return injectedCodeContains(overrideCallRegexCheck, TypeSystem::CodeSnipPositionAny,
                                 TypeSystem::NativeCode);
@@ -1529,13 +1565,13 @@ bool AbstractMetaFunction::injectedCodeHasReturnValueAttribution(TypeSystem::Lan
 {
     if (language == TypeSystem::TargetLangCode) {
         static const QRegularExpression
-            retValAttributionRegexCheck_target(QStringLiteral(R"(%PYARG_0\s*=[^=]\s*.+)"));
+            retValAttributionRegexCheck_target(R"(%PYARG_0\s*=[^=]\s*.+)"_L1);
         Q_ASSERT(retValAttributionRegexCheck_target.isValid());
         return injectedCodeContains(retValAttributionRegexCheck_target, TypeSystem::CodeSnipPositionAny, language);
     }
 
     static const QRegularExpression
-        retValAttributionRegexCheck_native(QStringLiteral(R"(%0\s*=[^=]\s*.+)"));
+        retValAttributionRegexCheck_native(R"(%0\s*=[^=]\s*.+)"_L1);
     Q_ASSERT(retValAttributionRegexCheck_native.isValid());
     return injectedCodeContains(retValAttributionRegexCheck_native, TypeSystem::CodeSnipPositionAny, language);
 }
@@ -1633,9 +1669,9 @@ void AbstractMetaFunction::formatDebugVerbose(QDebug &debug) const
         debug << " [userAdded]";
     if (isUserDeclared())
         debug << " [userDeclared]";
-    if (d->m_explicit)
+    if (d->m_cppAttributes.testFlag(FunctionAttribute::Explicit))
         debug << " [explicit]";
-    if (attributes().testFlag(AbstractMetaFunction::Deprecated))
+    if (d->m_cppAttributes.testFlag(FunctionAttribute::Deprecated))
         debug << " [deprecated]";
     if (d->m_pointerOperator)
         debug << " [operator->]";
index 1966ff33b3472c19c7a64d335cd313ed426d1dfa..e252e439dcf67273dd2a7dd4f9d1ca4c6bcced8d 100644 (file)
@@ -92,14 +92,8 @@ public:
     enum Attribute {
         None                        = 0x00000000,
 
-        Friendly                    = 0x00000001,
-
-        Abstract                    = 0x00000002,
-        Static                      = 0x00000004,
         ClassMethod                 = 0x00000008,
 
-        FinalInTargetLang           = 0x00000010,
-
         GetterFunction              = 0x00000020,
         SetterFunction              = 0x00000040,
 
@@ -108,14 +102,8 @@ public:
         PropertyResetter            = 0x00000400,
         PropertyNotify              = 0x00000800,
 
-        Invokable                   = 0x00001000,
-
-        VirtualCppMethod            = 0x00010000,
-        OverriddenCppMethod         = 0x00020000,
-        FinalCppMethod              = 0x00040000,
         // Add by meta builder (implicit constructors, inherited methods, etc)
         AddedMethod                 = 0x001000000,
-        Deprecated                  = 0x002000000 // Code annotation
     };
     Q_DECLARE_FLAGS(Attributes, Attribute)
     Q_FLAG(Attribute)
@@ -126,6 +114,10 @@ public:
     void operator+=(Attribute attribute);
     void operator-=(Attribute attribute);
 
+    FunctionAttributes cppAttributes() const;
+    void setCppAttributes(FunctionAttributes a);
+    void setCppAttribute(FunctionAttribute a, bool on = true);
+
     enum class Flag { // Internal flags not relevant for comparing functions
         // Binary operator whose leading/trailing argument was removed by metabuilder
         OperatorLeadingClassArgumentRemoved = 0x1,
@@ -140,11 +132,9 @@ public:
     Flags flags() const;
     void setFlags(Flags f);
 
-    bool isFinalInTargetLang() const;
     bool isAbstract() const;
     bool isClassMethod() const;
     bool isStatic() const;
-    bool isInvokable() const;
     bool isPropertyReader() const;
     bool isPropertyWriter() const;
     bool isPropertyResetter() const;
@@ -310,6 +300,7 @@ public:
 
     /// Returns true if the AbstractMetaFunction was added by the user via the type system description.
     bool isUserAdded() const;
+    bool isUserAddedPythonOverride() const;
     /// Returns true if the AbstractMetaFunction was declared by the user via
     /// the type system description.
     bool isUserDeclared() const;
@@ -387,13 +378,14 @@ public:
     void setPropertySpecIndex(int i);
 
     FunctionTypeEntryPtr typeEntry() const;
-
     void setTypeEntry(const FunctionTypeEntryPtr &typeEntry);
 
+    QString targetLangPackage() const;
+
     bool isCallOperator() const;
 
     static AbstractMetaFunctionCPtr
-        find(const AbstractMetaFunctionCList &haystack, QStringView needle);
+        find(const AbstractMetaFunctionCList &haystack, QAnyStringView needle);
 
     bool matches(OperatorQueryOptions) const;
 
@@ -452,19 +444,14 @@ private:
     QScopedPointer<AbstractMetaFunctionPrivate> d;
 };
 
-inline bool AbstractMetaFunction::isFinalInTargetLang() const
-{
-    return attributes().testFlag(FinalInTargetLang);
-}
-
 inline bool AbstractMetaFunction::isAbstract() const
 {
-    return attributes().testFlag(Abstract);
+    return cppAttributes().testFlag(FunctionAttribute::Abstract);
 }
 
 inline bool AbstractMetaFunction::isStatic() const
 {
-    return attributes().testFlag(Static);
+    return cppAttributes().testFlag(FunctionAttribute::Static);
 }
 
 inline bool AbstractMetaFunction::isClassMethod() const
@@ -472,11 +459,6 @@ inline bool AbstractMetaFunction::isClassMethod() const
     return attributes().testFlag(ClassMethod);
 }
 
-inline bool AbstractMetaFunction::isInvokable() const
-{
-    return attributes().testFlag(Invokable);
-}
-
 inline bool AbstractMetaFunction::isPropertyReader() const
 {
     return attributes().testFlag(PropertyReader);
index 87e215c8c38187930cd8ae9e1a927c436f94ef90..fb49cc9d0824bdfbd6db9215908d5872d7bcb062 100644 (file)
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
 #include "abstractmetalang.h"
+#include "anystringview_helpers.h"
 #include "abstractmetalang_helpers.h"
 #include "abstractmetaargument.h"
 #include "abstractmetaenum.h"
@@ -101,6 +102,7 @@ public:
 
     AbstractMetaClassCPtr m_templateBaseClass;
     AbstractMetaFunctionCList m_functions;
+    AbstractMetaFunctionCList m_userAddedPythonOverrides;
     AbstractMetaFieldList m_fields;
     AbstractMetaEnumList m_enums;
     QList<QPropertySpec> m_propertySpecs;
@@ -176,29 +178,16 @@ AbstractMetaFunctionCList AbstractMetaClass::functionsInTargetLang() const
     FunctionQueryOptions default_flags = FunctionQueryOption::NormalFunctions
         | FunctionQueryOption::Visible | FunctionQueryOption::NotRemoved;
 
-    // Only public functions in final classes
-    // default_flags |= isFinal() ? WasPublic : 0;
-    FunctionQueryOptions public_flags;
-    if (isFinalInTargetLang())
-        public_flags |= FunctionQueryOption::WasPublic;
-
     // Constructors
     AbstractMetaFunctionCList returned = queryFunctions(FunctionQueryOption::AnyConstructor
-                                                        | default_flags | public_flags);
-
-    // Final functions
-    returned += queryFunctions(FunctionQueryOption::FinalInTargetLangFunctions
-                               | FunctionQueryOption::NonStaticFunctions
-                               | default_flags | public_flags);
+                                                        | default_flags);
 
-    // Virtual functions
-    returned += queryFunctions(FunctionQueryOption::VirtualInTargetLangFunctions
-                               | FunctionQueryOption::NonStaticFunctions
-                               | default_flags | public_flags);
+    returned += queryFunctions(FunctionQueryOption::NonStaticFunctions
+                               | default_flags);
 
     // Static functions
     returned += queryFunctions(FunctionQueryOption::StaticFunctions
-                               | default_flags | public_flags);
+                               | default_flags);
 
     // Empty, private functions, since they aren't caught by the other ones
     returned += queryFunctions(FunctionQueryOption::Empty | FunctionQueryOption::Invisible);
@@ -335,6 +324,11 @@ const AbstractMetaFunctionCList &AbstractMetaClass::functions() const
     return d->m_functions;
 }
 
+const AbstractMetaFunctionCList &AbstractMetaClass::userAddedPythonOverrides() const
+{
+    return d->m_userAddedPythonOverrides;
+}
+
 void AbstractMetaClassPrivate::sortFunctions()
 {
     std::sort(m_functions.begin(), m_functions.end(), function_sorter);
@@ -402,7 +396,13 @@ void AbstractMetaClass::addFunction(const AbstractMetaClassPtr &klass,
     // to function properly. Such as function modifications
     nonConstF->setImplementingClass(klass);
 
-    klass->d->addFunction(function);
+    if (function->isUserAddedPythonOverride()) {
+        nonConstF->setConstant(false);
+        nonConstF->setCppAttribute(FunctionAttribute::Static);
+        klass->d->m_userAddedPythonOverrides.append(function);
+    } else {
+        klass->d->addFunction(function);
+    }
 }
 
 bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const
@@ -567,12 +567,12 @@ bool AbstractMetaClass::hasFunction(const QString &str) const
     return bool(findFunction(str));
 }
 
-AbstractMetaFunctionCPtr AbstractMetaClass::findFunction(QStringView functionName) const
+AbstractMetaFunctionCPtr AbstractMetaClass::findFunction(QAnyStringView functionName) const
 {
     return AbstractMetaFunction::find(d->m_functions, functionName);
 }
 
-AbstractMetaFunctionCList AbstractMetaClass::findFunctions(QStringView functionName) const
+AbstractMetaFunctionCList AbstractMetaClass::findFunctions(QAnyStringView functionName) const
 {
     AbstractMetaFunctionCList result;
     std::copy_if(d->m_functions.cbegin(), d->m_functions.cend(),
@@ -814,8 +814,7 @@ void AbstractMetaClassPrivate::addConstructor(AbstractMetaFunction::FunctionType
     auto *f = createFunction(q->name(), t, access, arguments, AbstractMetaType::createVoid(), q);
     if (access != Access::Private)
          m_hasNonPrivateConstructor = true;
-    f->setAttributes(AbstractMetaFunction::FinalInTargetLang
-                     | AbstractMetaFunction::AddedMethod);
+    f->setAttributes(AbstractMetaFunction::AddedMethod);
     addFunction(AbstractMetaFunctionCPtr(f));
 }
 
@@ -1168,24 +1167,15 @@ bool AbstractMetaClass::queryFunction(const AbstractMetaFunction *f, FunctionQue
     if (query.testFlag(FunctionQueryOption::Visible) && f->isPrivate())
         return false;
 
-    if (query.testFlag(FunctionQueryOption::VirtualInTargetLangFunctions) && f->isFinalInTargetLang())
-        return false;
-
     if (query.testFlag(FunctionQueryOption::Invisible) && !f->isPrivate())
         return false;
 
     if (query.testFlag(FunctionQueryOption::Empty) && !f->isEmptyFunction())
         return false;
 
-    if (query.testFlag(FunctionQueryOption::WasPublic) && !f->wasPublic())
-        return false;
-
     if (query.testFlag(FunctionQueryOption::ClassImplements) && f->ownerClass() != f->implementingClass())
         return false;
 
-    if (query.testFlag(FunctionQueryOption::FinalInTargetLangFunctions) && !f->isFinalInTargetLang())
-        return false;
-
     if (query.testFlag(FunctionQueryOption::VirtualInCppFunctions) && !f->isVirtual())
         return false;
 
@@ -1474,18 +1464,18 @@ void AbstractMetaClass::fixFunctions(const AbstractMetaClassPtr &klass)
     }
 
     for (const auto &superClassC : d->m_baseClasses) {
+        for (const auto &pof : superClassC->userAddedPythonOverrides()) {
+            auto *clonedPof = pof->copy();
+            clonedPof->setOwnerClass(klass);
+            d->m_userAddedPythonOverrides.append(AbstractMetaFunctionCPtr{clonedPof});
+        }
+
         auto superClass = std::const_pointer_cast<AbstractMetaClass>(superClassC);
         AbstractMetaClass::fixFunctions(superClass);
         // Since we always traverse the complete hierarchy we are only
         // interrested in what each super class implements, not what
         // we may have propagated from their base classes again.
         AbstractMetaFunctionCList superFuncs;
-        // Super classes can never be final
-        if (superClass->isFinalInTargetLang()) {
-            qCWarning(lcShiboken).noquote().nospace()
-                << "Final class '" << superClass->name() << "' set to non-final, as it is extended by other classes";
-            *superClass -= AbstractMetaClass::FinalInTargetLang;
-        }
         superFuncs = superClass->queryFunctions(FunctionQueryOption::ClassImplements);
         // We are not interested in signals as no bindings are generated for them;
         // they cause documentation warnings.
@@ -1520,29 +1510,11 @@ void AbstractMetaClass::fixFunctions(const AbstractMetaClassPtr &klass)
                     if (cmp & AbstractMetaFunction::EqualArguments) {
                         // Set "override" in case it was not spelled out (since it
                         // is then not detected by clang parsing).
-                        const auto attributes = cf->attributes();
-                        if (cf->isVirtual()
-                            && !attributes.testFlag(AbstractMetaFunction::OverriddenCppMethod)
-                            && !attributes.testFlag(AbstractMetaFunction::FinalCppMethod)) {
-                            *f += AbstractMetaFunction::OverriddenCppMethod;
-                        }
-                        // Same function, propegate virtual...
-                        if (!(cmp & AbstractMetaFunction::EqualAttributes)) {
-                            if (!f->isEmptyFunction()) {
-                                if (!sf->isFinalInTargetLang() && f->isFinalInTargetLang()) {
-                                    *f -= AbstractMetaFunction::FinalInTargetLang;
-                                }
-#if 0
-                                if (!f->isFinalInTargetLang() && f->isPrivate()) {
-                                    f->setFunctionType(AbstractMetaFunction::EmptyFunction);
-                                    f->setVisibility(AbstractMetaAttributes::Protected);
-                                    *f += AbstractMetaAttributes::FinalInTargetLang;
-                                    qCWarning(lcShiboken).noquote().nospace()
-                                        << QStringLiteral("private virtual function '%1' in '%2'")
-                                                          .arg(f->signature(), f->implementingClass()->name());
-                                }
-#endif
-                            }
+                        const auto attributes = cf->cppAttributes();
+                        if (attributes.testFlag(FunctionAttribute::Virtual)
+                            && !attributes.testFlag(FunctionAttribute::Override)
+                            && !attributes.testFlag(FunctionAttribute::Final)) {
+                            f->setCppAttribute(FunctionAttribute::Override);
                         }
 
                         if (f->access() != sf->access()) {
@@ -1559,44 +1531,12 @@ void AbstractMetaClass::fixFunctions(const AbstractMetaClassPtr &klass)
                             // Private overrides of abstract functions have to go into the class or
                             // the subclasses will not compile as non-abstract classes.
                             // But they don't need to be implemented, since they can never be called.
-                            if (f->isPrivate()) {
+                            if (f->isPrivate())
                                 f->setFunctionType(AbstractMetaFunction::EmptyFunction);
-                                *f += AbstractMetaFunction::FinalInTargetLang;
-                            }
                         }
 
                         // Set the class which first declares this function, afawk
                         f->setDeclaringClass(sf->declaringClass());
-
-                        if (sf->isFinalInTargetLang() && !sf->isPrivate() && !f->isPrivate() && !sf->isStatic() && !f->isStatic()) {
-                            // Shadowed funcion, need to make base class
-                            // function non-virtual
-                            if (f->implementingClass() != sf->implementingClass()
-                                && inheritsFrom(f->implementingClass(), sf->implementingClass())) {
-
-                                // Check whether the superclass method has been redefined to non-final
-
-                                bool hasNonFinalModifier = false;
-                                bool isBaseImplPrivate = false;
-                                const FunctionModificationList &mods = sf->modifications(sf->implementingClass());
-                                for (const FunctionModification &mod : mods) {
-                                    if (mod.isNonFinal()) {
-                                        hasNonFinalModifier = true;
-                                        break;
-                                    }
-                                    if (mod.isPrivate()) {
-                                        isBaseImplPrivate = true;
-                                        break;
-                                    }
-                                }
-
-                                if (!hasNonFinalModifier && !isBaseImplPrivate) {
-                                    qCWarning(lcShiboken, "%s",
-                                              qPrintable(msgShadowingFunction(sf.get(), f.get())));
-                                }
-                            }
-                        }
-
                     }
 
                     if (cmp & AbstractMetaFunction::EqualDefaultValueOverload) {
@@ -1675,6 +1615,7 @@ bool AbstractMetaClass::needsInheritanceSetup() const
         switch (d->m_typeEntry->type()) {
         case TypeEntry::NamespaceType:
         case TypeEntry::SmartPointerType:
+        case TypeEntry::ContainerType:
             return false;
         default:
             break;
@@ -1724,12 +1665,12 @@ std::optional<AbstractMetaEnumValue>
 /// Target language base name or complete Target language package.class name.
 
 template <class It>
-static It findClassHelper(It begin, It end, QStringView name)
+static It findClassHelper(It begin, It end, QAnyStringView name)
 {
     if (name.isEmpty() || begin == end)
         return end;
 
-    if (name.contains(u'.')) { // Search target lang name
+    if (asv_contains(name,'.')) { // Search target lang name
         for (auto it = begin; it != end; ++it) {
             if ((*it)->fullName() == name)
                 return it;
@@ -1742,7 +1683,7 @@ static It findClassHelper(It begin, It end, QStringView name)
             return it;
     }
 
-    if (name.contains(u"::")) // Qualified, cannot possibly match name
+    if (asv_contains(name, "::")) // Qualified, cannot possibly match name
         return end;
 
     for (auto it = begin; it != end; ++it) {
@@ -1754,14 +1695,14 @@ static It findClassHelper(It begin, It end, QStringView name)
 }
 
 AbstractMetaClassPtr AbstractMetaClass::findClass(const AbstractMetaClassList &classes,
-                                                  QStringView name)
+                                                  QAnyStringView name)
 {
     auto it =findClassHelper(classes.cbegin(), classes.cend(), name);
     return it != classes.cend() ? *it : nullptr;
 }
 
 AbstractMetaClassCPtr AbstractMetaClass::findClass(const AbstractMetaClassCList &classes,
-                                                   QStringView name)
+                                                   QAnyStringView name)
 {
     auto it = findClassHelper(classes.cbegin(), classes.cend(), name);
     return it != classes.cend() ? *it : nullptr;
@@ -1800,7 +1741,7 @@ bool inheritsFrom(const AbstractMetaClassCPtr &c, const AbstractMetaClassCPtr &c
     }));
 }
 
-bool inheritsFrom(const AbstractMetaClassCPtr &c, const QString &name)
+bool inheritsFrom(const AbstractMetaClassCPtr &c, QAnyStringView name)
 {
     if (c->qualifiedCppName() == name)
         return true;
@@ -2005,20 +1946,38 @@ QDebug operator<<(QDebug debug, const UsingMember &d)
     return debug;
 }
 
-QDebug operator<<(QDebug d, const AbstractMetaClassCPtr &ac)
+void formatMetaClass(QDebug &ddebug, const AbstractMetaClass *ac)
 {
-    QDebugStateSaver saver(d);
-    d.noquote();
-    d.nospace();
-    d << "AbstractMetaClass(";
-    if (ac) {
-        ac->format(d);
-        if (d.verbosity() > 2)
-            ac->formatMembers(d);
+    QDebugStateSaver saver(ddebug);
+    ddebug.noquote();
+    ddebug.nospace();
+    ddebug << "AbstractMetaClass(";
+    if (ac != nullptr) {
+        ac->format(ddebug);
+        if (ddebug.verbosity() > 2)
+            ac->formatMembers(ddebug);
     } else {
-        d << '0';
+        ddebug << '0';
     }
-    d << ')';
+    ddebug << ')';
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaClassCPtr &ac)
+{
+    formatMetaClass(d, ac.get());
     return d;
 }
+
+QDebug operator<<(QDebug d, const AbstractMetaClassPtr &ac)
+{
+    formatMetaClass(d, ac.get());
+    return d;
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaClass *ac)
+{
+    formatMetaClass(d, ac);
+    return d;
+}
+
 #endif // !QT_NO_DEBUG_STREAM
index d5071a283d67fd4b3e31423974e6f58a9d961ff7..3dc876690527eaf4663f57ac054b22533fe33dda 100644 (file)
@@ -66,12 +66,13 @@ public:
     ~AbstractMetaClass();
 
     const AbstractMetaFunctionCList &functions() const;
+    const AbstractMetaFunctionCList &userAddedPythonOverrides() const;
     void setFunctions(const AbstractMetaFunctionCList &functions);
     static void addFunction(const AbstractMetaClassPtr &klass,
                             const AbstractMetaFunctionCPtr &function);
     bool hasFunction(const QString &str) const;
-    AbstractMetaFunctionCPtr findFunction(QStringView functionName) const;
-    AbstractMetaFunctionCList findFunctions(QStringView functionName) const;
+    AbstractMetaFunctionCPtr findFunction(QAnyStringView functionName) const;
+    AbstractMetaFunctionCList findFunctions(QAnyStringView functionName) const;
     AbstractMetaFunctionCPtr findOperatorBool() const;
     // Find a Qt-style isNull() method suitable for nb_bool
     AbstractMetaFunctionCPtr findQtIsNullMethod() const;
@@ -315,9 +316,9 @@ public:
                                                           bool avoidProtectedHack);
 
     static AbstractMetaClassPtr findClass(const AbstractMetaClassList &classes,
-                                        QStringView name);
+                                          QAnyStringView name);
     static AbstractMetaClassCPtr findClass(const AbstractMetaClassCList &classes,
-                                              QStringView name);
+                                           QAnyStringView name);
     static AbstractMetaClassPtr findClass(const AbstractMetaClassList &classes,
                                         const TypeEntryCPtr &typeEntry);
     static AbstractMetaClassCPtr findClass(const AbstractMetaClassCList &classes,
@@ -344,16 +345,14 @@ private:
     void format(QDebug &d) const;
     void formatMembers(QDebug &d) const;
     friend QDebug operator<<(QDebug d, const AbstractMetaClassCPtr &ac);
+    friend QDebug operator<<(QDebug d, const AbstractMetaClassPtr &ac);
+    friend QDebug operator<<(QDebug d, const AbstractMetaClass *ac);
+    friend void formatMetaClass(QDebug &, const AbstractMetaClass *);
 #endif
 
     QScopedPointer<AbstractMetaClassPrivate> d;
 };
 
-inline bool AbstractMetaClass::isFinalInTargetLang() const
-{
-    return attributes().testFlag(FinalInTargetLang);
-}
-
 inline bool AbstractMetaClass::isAbstract() const
 {
     return attributes().testFlag(Abstract);
@@ -371,10 +370,10 @@ void AbstractMetaClass::invisibleNamespaceRecursion(Function f) const
 }
 
 bool inheritsFrom(const AbstractMetaClassCPtr &c, const AbstractMetaClassCPtr &other);
-bool inheritsFrom(const AbstractMetaClassCPtr &c, const QString &name);
+bool inheritsFrom(const AbstractMetaClassCPtr &c, QAnyStringView name);
 inline bool isQObject(const AbstractMetaClassCPtr &c)
 {
-    return inheritsFrom(c, QStringLiteral("QObject"));
+    return inheritsFrom(c, "QObject");
 }
 
 AbstractMetaClassCPtr findBaseClass(const AbstractMetaClassCPtr &c,
index 2bdfdb54db19f9146af03a01858b0e39e3bb0bb1..9047c6bcd7d0508ca62517291ab896b9784aa77e 100644 (file)
@@ -11,18 +11,15 @@ enum class FunctionQueryOption {
     Constructors                 = 0x0000002, // Constructors except copy/move
     CopyConstructor              = 0x0000004, // Only copy constructors
     //Destructors                  = 0x0000002, // Only destructors. Not included in class.
-    FinalInTargetLangFunctions   = 0x0000008, // Only functions that are non-virtual in TargetLang
     ClassImplements              = 0x0000020, // Only functions implemented by the current class
     StaticFunctions              = 0x0000080, // Only static functions
     Signals                      = 0x0000100, // Only signals
     NormalFunctions              = 0x0000200, // Only functions that aren't signals
     Visible                      = 0x0000400, // Only public and protected functions
-    WasPublic                    = 0x0001000, // Only functions that were originally public
     NonStaticFunctions           = 0x0004000, // No static functions
     Empty                        = 0x0008000, // Empty overrides of abstract functions
     Invisible                    = 0x0010000, // Only private functions
     VirtualInCppFunctions        = 0x0020000, // Only functions that are virtual in C++
-    VirtualInTargetLangFunctions = 0x0080000, // Only functions which are virtual in TargetLang
     NotRemoved                   = 0x0400000, // Only functions that have not been removed
     OperatorOverloads            = 0x2000000, // Only functions that are operator overloads
     GenerateExceptionHandling    = 0x4000000,
index d9f5bde4106fa43e42ea5b61555eb66226113a94..3ec07509d179de372353c1a09fcb19e3e32aec54 100644 (file)
@@ -543,6 +543,7 @@ void AbstractMetaType::decideUsagePattern()
         pattern = ObjectPattern;
     }
     setTypeUsagePattern(pattern);
+    Q_ASSERT(pattern != ContainerPattern || !d->m_instantiations.isEmpty());
 }
 
 bool AbstractMetaTypeData::hasTemplateChildren() const
@@ -778,9 +779,9 @@ bool AbstractMetaTypeData::equals(const AbstractMetaTypeData &rhs) const
         && m_referenceType == rhs.m_referenceType && isEquivalent(rhs);
 }
 
-bool AbstractMetaType::equals(const AbstractMetaType &rhs) const
+bool comparesEqual(const AbstractMetaType &lhs, const AbstractMetaType &rhs) noexcept
 {
-    return d->equals(*rhs.d);
+    return lhs.d->equals(*rhs.d);
 }
 
 bool AbstractMetaType::isEquivalent(const AbstractMetaType &rhs) const
@@ -948,14 +949,18 @@ using AbstractMetaTypeCache = QHash<QString, AbstractMetaType>;
 Q_GLOBAL_STATIC(AbstractMetaTypeCache, metaTypeFromStringCache)
 
 std::optional<AbstractMetaType>
-AbstractMetaType::fromString(QString typeSignature, QString *errorMessage)
+AbstractMetaType::fromString(const QString &typeSignatureIn, QString *errorMessage)
 {
-    typeSignature = typeSignature.trimmed();
+    auto &cache = *metaTypeFromStringCache();
+    auto it = cache.find(typeSignatureIn);
+    if (it != cache.end())
+        return it.value();
+
+    QString typeSignature = typeSignatureIn.trimmed();
     if (typeSignature.startsWith(u"::"))
         typeSignature.remove(0, 2);
 
-    auto &cache = *metaTypeFromStringCache();
-    auto it = cache.find(typeSignature);
+    it = cache.find(typeSignature);
     if (it == cache.end()) {
         auto metaType =
             AbstractMetaBuilder::translateType(typeSignature, nullptr, {}, errorMessage);
@@ -964,6 +969,8 @@ AbstractMetaType::fromString(QString typeSignature, QString *errorMessage)
                 errorMessage->prepend(msgCannotBuildMetaType(typeSignature));
             return {};
         }
+        if (typeSignature != typeSignatureIn)
+            cache.insert(typeSignatureIn, metaType.value());
         it = cache.insert(typeSignature, metaType.value());
     }
     return it.value();
index dd3d96bf8ab7d51a71998e64b3d744da6f599e97..8a1ecdf205993642973ae89e301c08c89128cc16 100644 (file)
@@ -9,6 +9,7 @@
 #include "parser/codemodel_enums.h"
 #include "typedatabase_typedefs.h"
 
+#include <QtCore/QtCompare>
 #include <QtCore/qobjectdefs.h>
 #include <QtCore/QHashFunctions>
 #include <QtCore/QSharedDataPointer>
@@ -171,7 +172,6 @@ public:
 
     bool hasTemplateChildren() const;
 
-    bool equals(const AbstractMetaType &rhs) const;
     /// Is equivalent from the POV of argument passing (differ by const ref)
     bool isEquivalent(const AbstractMetaType &rhs) const;
 
@@ -188,7 +188,7 @@ public:
     /// \param typeSignature The string describing the type to be built.
     /// \return A new AbstractMetaType object or nullopt in case of failure.
     static std::optional<AbstractMetaType>
-        fromString(QString typeSignature, QString *errorMessage = nullptr);
+        fromString(const QString &typeSignatureIn, QString *errorMessage = nullptr);
     /// Creates an AbstractMetaType object from a TypeEntry.
     static AbstractMetaType fromTypeEntry(const TypeEntryCPtr &typeEntry);
     /// Creates an AbstractMetaType object from an AbstractMetaClass.
@@ -256,6 +256,9 @@ public:
 private:
     friend size_t qHash(const AbstractMetaType &t, size_t seed = 0) noexcept
     { return qHash(t.typeEntry().get(), seed); }
+    friend bool comparesEqual(const AbstractMetaType &lhs,
+                              const AbstractMetaType &rhs) noexcept;
+    Q_DECLARE_EQUALITY_COMPARABLE(AbstractMetaType)
 
     friend class AbstractMetaTypeData;
     QSharedDataPointer<AbstractMetaTypeData> d;
@@ -265,11 +268,6 @@ private:
     QString formatPythonSignature() const;
 };
 
-inline bool operator==(const AbstractMetaType &t1, const AbstractMetaType &t2)
-{ return t1.equals(t2); }
-inline bool operator!=(const AbstractMetaType &t1, const AbstractMetaType &t2)
-{ return !t1.equals(t2); }
-
 #ifndef QT_NO_DEBUG_STREAM
 QDebug operator<<(QDebug d, const AbstractMetaType &at);
 QDebug operator<<(QDebug d, const AbstractMetaType *at);
index efb5fb99735886d7a5508d15626c55121314fc49..9d95b734ccea5e5c58b59a29d4e7072777320301 100644 (file)
@@ -9,18 +9,13 @@
 
 using namespace Qt::StringLiterals;
 
-static inline QString callOperator() { return QStringLiteral("operator()"); }
+constexpr auto callOperator = "operator()"_L1;
 
 // Helpers to split a parameter list of <add-function>, <declare-function>
 // (@ denoting names), like
 // "void foo(QList<X,Y> &@list@ = QList<X,Y>{1,2}, int @b@=5, ...)"
 namespace AddedFunctionParser {
 
-bool Argument::equals(const Argument &rhs) const
-{
-    return type == rhs.type && name == rhs.name && defaultValue == rhs.defaultValue;
-}
-
 QDebug operator<<(QDebug d, const Argument &a)
 {
     QDebugStateSaver saver(d);
@@ -143,8 +138,8 @@ AddedFunction::AddedFunctionPtr
     QStringView signature = QStringView{signatureIn}.trimmed();
 
     // Skip past "operator()(...)"
-    const auto parenSearchStartPos = signature.startsWith(callOperator())
-        ? callOperator().size() : 0;
+    const auto parenSearchStartPos = signature.startsWith(callOperator)
+        ? callOperator.size() : 0;
     const auto openParenPos = signature.indexOf(u'(', parenSearchStartPos);
     if (openParenPos < 0) {
         return AddedFunctionPtr(new AddedFunction(signature.toString(),
index 8a0475f33ee668f877f9a56c436b43540b220abd..b8d189b7a62e3f6248b8ce991fdee1f440b2513f 100644 (file)
@@ -79,6 +79,9 @@ struct AddedFunction
     bool isDeclaration() const { return m_isDeclaration; } // <declare-function>
     void setDeclaration(bool value) { m_isDeclaration = value; }
 
+    bool isPythonOverride() const { return m_isPythonOverride; }
+    void setPythonOverride(bool o) { m_isPythonOverride = o; }
+
     const FunctionModificationList &modifications() const { return m_modifications; }
     FunctionModificationList &modifications() { return m_modifications; }
 
@@ -86,17 +89,22 @@ struct AddedFunction
     DocModificationList &docModifications() { return m_docModifications; }
     void addDocModification(const DocModification &m) { m_docModifications.append(m); }
 
+    QString targetLangPackage() const { return m_targetLangPackage; }
+    void setTargetLangPackage(const QString &p) { m_targetLangPackage = p; }
+
 private:
     QString m_name;
     QList<Argument> m_arguments;
     TypeInfo m_returnType;
     FunctionModificationList m_modifications;
     DocModificationList m_docModifications;
+    QString m_targetLangPackage;
     Access m_access = Public;
     bool m_isConst = false;
     bool m_isClassMethod = false;
     bool m_isStatic = false;
     bool m_isDeclaration = false;
+    bool m_isPythonOverride = false;
 };
 
 QDebug operator<<(QDebug d, const AddedFunction::Argument &a);
index 9915871ade671ac80b2d0b13a956d3896143ade0..40b69a5dfa857ac88548d2a8befc2193502b9fc9 100644 (file)
@@ -4,6 +4,7 @@
 #ifndef ADDEDFUNCTION_P_H
 #define ADDEDFUNCTION_P_H
 
+#include <QtCore/QtCompare>
 #include <QtCore/QList>
 #include <QtCore/QString>
 #include <QtCore/QStringView>
@@ -19,18 +20,20 @@ namespace AddedFunctionParser {
 
 struct Argument
 {
-    bool equals(const Argument &rhs) const;
-
     QString type;
     QString name;
     QString defaultValue;
+
+    friend bool comparesEqual(const Argument &lhs, const Argument &rhs) noexcept
+    {
+        return lhs.type == rhs.type && lhs.name == rhs.name
+               && lhs.defaultValue == rhs.defaultValue;
+    }
+    Q_DECLARE_EQUALITY_COMPARABLE(Argument)
 };
 
 using Arguments = QList<Argument>;
 
-inline bool operator==(const Argument &a1, const Argument &a2) { return a1.equals(a2); }
-inline bool operator!=(const Argument &a1, const Argument &a2) { return !a1.equals(a2); }
-
 #ifndef QT_NO_DEBUG_STREAM
 QDebug operator<<(QDebug d, const Argument &a);
 #endif
diff --git a/sources/shiboken6/ApiExtractor/anystringview_helpers.cpp b/sources/shiboken6/ApiExtractor/anystringview_helpers.cpp
new file mode 100644 (file)
index 0000000..35d2d53
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "anystringview_helpers.h"
+
+#include <QtCore/QString> // Must go before QAnyStringView for operator<<(QTextStream,QASV)!
+#include <QtCore/QAnyStringView>
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+
+#include <cstring>
+
+QTextStream &operator<<(QTextStream &str, QAnyStringView asv)
+{
+    asv.visit([&str](auto s) { str << s; });
+    return str;
+}
+
+static bool asv_containsImpl(QLatin1StringView v, char c)
+{
+    return v.contains(uint16_t(c));
+}
+
+static bool asv_containsImpl(QUtf8StringView v, char c)
+{
+    return std::strchr(v.data(), c) != nullptr;
+}
+
+static bool asv_containsImpl(QStringView v, char c)
+{
+    return v.contains(uint16_t(c));
+}
+
+bool asv_contains(QAnyStringView asv, char needle)
+{
+    return asv.visit([needle](auto s) { return asv_containsImpl(s, needle); });
+}
+
+static bool asv_containsImpl(QLatin1StringView v, const char *c)
+{
+    return v.contains(QLatin1StringView(c));
+}
+static bool asv_containsImpl(QUtf8StringView v, const char *c)
+{
+    return std::strstr(v.data(), c) != nullptr;
+}
+
+static bool asv_containsImpl(QStringView v, const char *c)
+{
+    return v.contains(QLatin1StringView(c));
+}
+
+bool asv_contains(QAnyStringView asv, const char *needle)
+{
+    return asv.visit([needle](auto s) { return asv_containsImpl(s, needle); });
+}
diff --git a/sources/shiboken6/ApiExtractor/anystringview_helpers.h b/sources/shiboken6/ApiExtractor/anystringview_helpers.h
new file mode 100644 (file)
index 0000000..e1e6ab7
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ANYSTRINGVIEW_STREAM_H
+#define ANYSTRINGVIEW_STREAM_H
+
+#include <QtCore/QtClassHelperMacros>
+
+QT_FORWARD_DECLARE_CLASS(QAnyStringView)
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+QTextStream &operator<<(QTextStream &str, QAnyStringView asv);
+
+bool asv_contains(QAnyStringView asv, char needle);
+bool asv_contains(QAnyStringView asv, const char *needle);
+
+#endif // ANYSTRINGVIEW_STREAM_H
index cf1b59b8822b1aa44c74d216f803f87748aefd4f..a4efaf2f9786d1d33499c2f6d662d8a6aafc214e 100644 (file)
@@ -340,8 +340,7 @@ bool ApiExtractorPrivate::runHelper(ApiExtractorFlags flags)
     }
 
     const QString pattern = QDir::tempPath() + u'/'
-        + m_cppFileNames.constFirst().baseName()
-        + QStringLiteral("_XXXXXX.hpp");
+        + m_cppFileNames.constFirst().baseName() + "_XXXXXX.hpp"_L1;
     QTemporaryFile ppFile(pattern);
     bool autoRemove = !qEnvironmentVariableIsSet("KEEP_TEMP_FILES");
     // make sure that a tempfile can be written
@@ -422,6 +421,7 @@ std::optional<ApiExtractorResult> ApiExtractor::run(ApiExtractorFlags flags)
     result.m_globalEnums = d->m_builder->globalEnums();
     result.m_enums = d->m_builder->typeEntryToEnumsHash();
     result.m_flags = flags;
+    result.m_typedefTargetToName = d->m_builder->typedefTargetToName();
     qSwap(result.m_instantiatedContainers, collectContext.instantiatedContainers);
     qSwap(result.m_instantiatedSmartPointers, collectContext.instantiatedSmartPointers);
     return result;
@@ -456,11 +456,10 @@ AbstractMetaFunctionPtr
 
 AbstractMetaClassPtr ApiExtractor::inheritTemplateClass(const ComplexTypeEntryPtr &te,
                                                       const AbstractMetaClassCPtr &templateClass,
-                                                      const AbstractMetaTypeList &templateTypes,
-                                                      InheritTemplateFlags flags)
+                                                      const AbstractMetaTypeList &templateTypes)
 {
     return AbstractMetaBuilder::inheritTemplateClass(te, templateClass,
-                                                     templateTypes, flags);
+                                                     templateTypes);
 }
 
 QString ApiExtractorPrivate::getSimplifiedContainerTypeName(const AbstractMetaType &type)
@@ -534,12 +533,12 @@ ApiExtractorPrivate::addInstantiatedContainersAndSmartPointers(InstantiationColl
         return;
     }
     if (type.hasTemplateChildren()) {
-        QString piece = isContainer ? QStringLiteral("container") : QStringLiteral("smart pointer");
+        const auto piece = isContainer ? "container"_L1 : "smart pointer"_L1;
         QString warning =
             QString::fromLatin1("Skipping instantiation of %1 '%2' because it has template"
                                 " arguments.").arg(piece, type.originalTypeDescription());
         if (!contextName.isEmpty())
-            warning.append(QStringLiteral(" Calling context: ") + contextName);
+            warning.append(" Calling context: "_L1 + contextName);
 
         qCWarning(lcShiboken).noquote().nospace() << warning;
         return;
@@ -606,7 +605,6 @@ void ApiExtractorPrivate::addInstantiatedSmartPointer(InstantiationCollectContex
     const auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(smp.smartPointer->typeEntry());
     QString name = ste->getTargetName(smp.type);
     auto parentTypeEntry = ste->parent();
-    InheritTemplateFlags flags;
 
     auto colonPos = name.lastIndexOf(u"::");
     const bool withinNameSpace = colonPos != -1;
@@ -617,19 +615,18 @@ void ApiExtractorPrivate::addInstantiatedSmartPointer(InstantiationCollectContex
         if (nameSpaces.isEmpty())
             throw Exception(msgNamespaceNotFound(name));
         parentTypeEntry = nameSpaces.constFirst();
-    } else {
-        flags.setFlag(InheritTemplateFlag::SetEnclosingClass);
     }
 
     TypedefEntryPtr typedefEntry(new TypedefEntry(name, ste->name(), ste->version(),
                                                   parentTypeEntry));
     typedefEntry->setTargetLangPackage(ste->targetLangPackage());
     auto instantiationEntry = TypeDatabase::initializeTypeDefEntry(typedefEntry, ste);
+    instantiationEntry->setParent(parentTypeEntry);
 
     smp.specialized = ApiExtractor::inheritTemplateClass(instantiationEntry, smp.smartPointer,
-                                                         {instantiatedType}, flags);
+                                                         {instantiatedType});
     Q_ASSERT(smp.specialized);
-    if (withinNameSpace) { // move class to desired namespace
+    if (parentTypeEntry->type() != TypeEntry::TypeSystemType) { // move class to desired namespace
         const auto enclClass = AbstractMetaClass::findClass(m_builder->classes(), parentTypeEntry);
         Q_ASSERT(enclClass);
         auto specialized = std::const_pointer_cast<AbstractMetaClass>(smp.specialized);
@@ -669,6 +666,8 @@ ApiExtractorPrivate::collectInstantiatedContainersAndSmartPointers(Instantiation
         return;
     for (const auto &func : metaClass->functions())
         collectInstantiatedContainersAndSmartPointers(context, func);
+    for (const auto &func : metaClass->userAddedPythonOverrides())
+        collectInstantiatedContainersAndSmartPointers(context, func);
     for (const AbstractMetaField &field : metaClass->fields())
         addInstantiatedContainersAndSmartPointers(context, field.type(), field.name());
 
index feae9454cb6a95e51e82d0518dad28d587861690..7bff5c25297dbc083f1de1c90715a4e943696386 100644 (file)
@@ -73,8 +73,7 @@ public:
     static AbstractMetaClassPtr
         inheritTemplateClass(const ComplexTypeEntryPtr &te,
                              const AbstractMetaClassCPtr &templateClass,
-                             const AbstractMetaTypeList &templateTypes,
-                             InheritTemplateFlags flags = {});
+                             const AbstractMetaTypeList &templateTypes);
 
 private:
     ApiExtractorPrivate *d;
index 4fe6ecc1af3ed16f4f494bd52f7d4e17b44e5725..6f69b8b77f1d52484f956f653bdf752372058fd8 100644 (file)
@@ -15,12 +15,4 @@ enum class ApiExtractorFlag
 Q_DECLARE_FLAGS(ApiExtractorFlags, ApiExtractorFlag)
 Q_DECLARE_OPERATORS_FOR_FLAGS(ApiExtractorFlags)
 
-enum class InheritTemplateFlag
-{
-    SetEnclosingClass = 0x1
-};
-
-Q_DECLARE_FLAGS(InheritTemplateFlags, InheritTemplateFlag)
-Q_DECLARE_OPERATORS_FOR_FLAGS(InheritTemplateFlags)
-
 #endif // APIEXTRACTORFLAGS_H
index eb9ac2d4adf86dbf1e719c5341ce8386c9e082f4..5a433bbeb8a5eccc1959c9c5522dd7ffbb508b41 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "enumtypeentry.h"
 #include "flagstypeentry.h"
+#include "smartpointertypeentry.h"
 
 ApiExtractorResult::ApiExtractorResult() = default;
 
@@ -50,6 +51,23 @@ const InstantiatedSmartPointers &ApiExtractorResult::instantiatedSmartPointers()
     return m_instantiatedSmartPointers;
 }
 
+std::optional<InstantiatedSmartPointer>
+    ApiExtractorResult::findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer,
+                                                      const TypeEntryCPtr &pointee) const
+{
+    for (const auto &smp : m_instantiatedSmartPointers) {
+        const auto &i = smp.type;
+        if (i.typeEntry() == pointer && i.instantiations().at(0).typeEntry() == pointee)
+            return smp;
+    }
+    return std::nullopt;
+}
+
+const QMultiHash<QString, QString> &ApiExtractorResult::typedefTargetToName() const
+{
+    return m_typedefTargetToName;
+}
+
 ApiExtractorFlags ApiExtractorResult::flags() const
 {
     return m_flags;
index c1bb1a0a08689a366f822f637148681b5b97de49..b2aae88ed1cf70877d00ca38310073aaad133c49 100644 (file)
@@ -10,6 +10,7 @@
 #include "typesystem_typedefs.h"
 
 #include <QtCore/QHash>
+#include <QtCore/QMultiHash>
 
 #include <optional>
 
@@ -42,6 +43,11 @@ public:
 
     const AbstractMetaTypeList &instantiatedContainers() const;
     const InstantiatedSmartPointers &instantiatedSmartPointers() const;
+    std::optional<InstantiatedSmartPointer>
+        findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer,
+                                      const TypeEntryCPtr &pointee) const;
+
+    const QMultiHash<QString, QString> &typedefTargetToName() const;
 
     // Query functions for the generators
     std::optional<AbstractMetaEnum>
@@ -66,6 +72,7 @@ private:
     AbstractMetaTypeList m_instantiatedContainers;
     InstantiatedSmartPointers m_instantiatedSmartPointers;
     QHash<TypeEntryCPtr, AbstractMetaEnum> m_enums;
+    QMultiHash<QString, QString> m_typedefTargetToName;
     ApiExtractorFlags m_flags;
 
     friend class ApiExtractor;
index 57604ceacc3ca72d65e57f6501f569c1ace8b524..31e7efb05555805f8fd71b5888c8338a75edf074 100644 (file)
@@ -26,8 +26,6 @@ using namespace Qt::StringLiterals;
 
 namespace clang {
 
-static inline QString templateBrackets() { return QStringLiteral("<>"); }
-
 static inline bool isClassCursor(const CXCursor &c)
 {
     return c.kind == CXCursor_ClassDecl || c.kind == CXCursor_StructDecl
@@ -274,7 +272,7 @@ static QString msgCannotDetermineException(const std::string_view &snippetV)
     const qsizetype length = qsizetype(truncate ? newLine : snippetV.size());
     QString snippet = QString::fromUtf8(snippetV.data(), length);
     if (truncate)
-        snippet += QStringLiteral("...");
+        snippet += "..."_L1;
 
     return u"Cannot determine exception specification: \""_s + snippet + u'"';
 }
@@ -348,7 +346,7 @@ FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor,
     case CXAvailability_Available:
         break;
     case CXAvailability_Deprecated:
-        result->setDeprecated(true);
+        result->setAttribute(FunctionAttribute::Deprecated);
         break;
     case CXAvailability_NotAvailable: // "Foo(const Foo&) = delete;"
         result->setDeleted(true);
@@ -391,9 +389,9 @@ FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor,
     auto result = createFunction(cursor, functionType, isTemplateCode);
     result->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
     result->setConstant(clang_CXXMethod_isConst(cursor) != 0);
-    result->setStatic(clang_CXXMethod_isStatic(cursor) != 0);
-    result->setVirtual(clang_CXXMethod_isVirtual(cursor) != 0);
-    result->setAbstract(clang_CXXMethod_isPureVirtual(cursor) != 0);
+    result->setAttribute(FunctionAttribute::Static, clang_CXXMethod_isStatic(cursor) != 0);
+    result->setAttribute(FunctionAttribute::Virtual, clang_CXXMethod_isVirtual(cursor) != 0);
+    result->setAttribute(FunctionAttribute::Abstract, clang_CXXMethod_isPureVirtual(cursor) != 0);
     return result;
 }
 
@@ -409,7 +407,8 @@ void BuilderPrivate::qualifyConstructor(const CXCursor &cursor)
         && m_currentFunction->arguments().size() == 1
         && clang_CXXConstructor_isCopyConstructor(cursor) == 0
         && clang_CXXConstructor_isMoveConstructor(cursor) == 0) {
-        m_currentFunction->setExplicit(clang_CXXConstructor_isConvertingConstructor(cursor) == 0);
+        m_currentFunction->setAttribute(FunctionAttribute::Explicit,
+                                        clang_CXXConstructor_isConvertingConstructor(cursor) == 0);
     }
 }
 
@@ -433,6 +432,7 @@ void BuilderPrivate::addField(const CXCursor &cursor)
     field->setScope(m_scope);
     field->setType(createTypeInfo(cursor));
     field->setMutable(clang_CXXField_isMutable(cursor) != 0);
+    setFileName(cursor, field.get());
     m_currentField = field;
     m_scopeStack.back()->addVariable(field);
 }
@@ -969,15 +969,15 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
             || !d->addClass(cursor, CodeModel::Class)) {
             return Skip;
         }
-        d->m_currentClass->setName(d->m_currentClass->name() + templateBrackets());
-        d->m_scope.back() += templateBrackets();
+        d->m_currentClass->setName(d->m_currentClass->name() + "<>"_L1);
+        d->m_scope.back() += "<>"_L1;
         break;
     case CXCursor_EnumDecl: {
         QString name = enumType(cursor);
         EnumKind kind = CEnum;
         if (name.isEmpty()) {
             kind = AnonymousEnum;
-            name = QStringLiteral("enum_") + QString::number(++d->m_anonymousEnumCount);
+            name = "enum_"_L1 + QString::number(++d->m_anonymousEnumCount);
 #if !CLANG_NO_ENUMDECL_ISSCOPED
         } else if (clang_EnumDecl_isScoped(cursor) != 0) {
 #else
@@ -1059,6 +1059,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
         }
     }
         d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, true);
+        d->setFileName(cursor, d->m_currentFunction.get());
         d->m_scopeStack.back()->addFunction(d->m_currentFunction);
         break;
     case CXCursor_FunctionDecl:
@@ -1134,8 +1135,8 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
             const QString &tplParmName = tItem->name();
             if (Q_UNLIKELY(!insertTemplateParameterIntoClassName(tplParmName, d->m_currentClass)
                            || !insertTemplateParameterIntoClassName(tplParmName, &d->m_scope.back()))) {
-                const QString message = QStringLiteral("Error inserting template parameter \"") + tplParmName
-                        + QStringLiteral("\" into ") + d->m_currentClass->name();
+                const QString message = "Error inserting template parameter \""_L1 + tplParmName
+                        + "\" into "_L1 + d->m_currentClass->name();
                 const Diagnostic d(message, cursor, CXDiagnostic_Error);
                 qWarning() << d;
                 appendDiagnostic(d);
@@ -1182,13 +1183,13 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
         break;
     case CXCursor_CXXFinalAttr:
          if (d->m_currentFunction)
-             d->m_currentFunction->setFinal(true);
+            d->m_currentFunction->setAttribute(FunctionAttribute::Final);
          else if (d->m_currentClass)
              d->m_currentClass->setFinal(true);
         break;
     case CXCursor_CXXOverrideAttr:
         if (d->m_currentFunction)
-            d->m_currentFunction->setOverride(true);
+            d->m_currentFunction->setAttribute(FunctionAttribute::Override);
         break;
     case CXCursor_StaticAssert:
         // Check for Q_PROPERTY() (see PySide6/global.h.in for an explanation
index 3a1b91e1ab0523ff5d2f003ac9181d248617a9c4..7aac8a57512f3d4d8adc5c3c12a6aaf9764e679c 100644 (file)
@@ -4,7 +4,7 @@
 #ifndef CLANGDEBUGUTILS_H
 #define CLANGDEBUGUTILS_H
 
-#include <QtCore/QtGlobal>
+#include <QtCore/qtclasshelpermacros.h>
 
 #include <clang-c/Index.h>
 
index 9762b352f3b5f8b64d557afb9183572b05846502..da6930476cd2bd19d97ccc991b917c73406415b7 100644 (file)
@@ -13,6 +13,8 @@
 #include <QtCore/QScopedArrayPointer>
 #include <QtCore/QString>
 
+using namespace Qt::StringLiterals;
+
 namespace clang {
 
 QString SourceFileCache::getFileName(CXFile file)
@@ -39,7 +41,7 @@ std::string_view SourceFileCache::getCodeSnippet(const CXCursor &cursor,
 
     if (range.first.file != range.second.file) {
         if (errorMessage)
-            *errorMessage = QStringLiteral("Range spans several files");
+            *errorMessage = "Range spans several files"_L1;
         return std::string_view(empty, 0);
     }
 
@@ -48,7 +50,7 @@ std::string_view SourceFileCache::getCodeSnippet(const CXCursor &cursor,
         const QString fileName = getFileName(range.first.file);
         if (fileName.isEmpty()) {
             if (errorMessage)
-                 *errorMessage = QStringLiteral("Range has no file");
+                 *errorMessage = "Range has no file"_L1;
             return std::string_view(empty, 0);
         }
         QFile file(fileName);
index 4e1f1ab632049c39088f0f58a36c43701c683040..1651e09ece8ed279530edc679486e3e9d1ce4605 100644 (file)
@@ -35,11 +35,6 @@ size_t qHash(const CXType &ct, size_t seed) noexcept
 
 namespace clang {
 
-bool SourceLocation::equals(const SourceLocation &rhs) const
-{
-    return file == rhs.file && offset == rhs.offset;
-}
-
 SourceLocation getExpansionLocation(const CXSourceLocation &location)
 {
     SourceLocation result;
index eaa04daed7e5f46154b60f99790debb9b2a21074..fbbf95f1bda993583d2319c6c485a42ccdf5c177 100644 (file)
@@ -7,6 +7,7 @@
 #include <clang-c/Index.h>
 #include <QtCore/QString>
 #include <QtCore/QStringList>
+#include <QtCore/QtCompare>
 #include <QtCore/QList>
 
 #include <functional>
@@ -49,13 +50,14 @@ struct SourceLocation
     unsigned line = 0;
     unsigned column = 0;
     unsigned offset = 0;
-};
-
-inline bool operator==(const SourceLocation &l1, const SourceLocation &l2)
-{ return l1.equals(l2); }
 
-inline bool operator!=(const SourceLocation &l1, const SourceLocation &l2)
-{ return !l1.equals(l2); }
+    friend constexpr bool comparesEqual(const SourceLocation &lhs,
+                                        const SourceLocation &rhs) noexcept
+    {
+        return lhs.file == rhs.file && lhs.offset == rhs.offset;
+    }
+    Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(SourceLocation)
+};
 
 SourceLocation getExpansionLocation(const CXSourceLocation &location);
 
index d613739125057350f1c0cdbbfe5a6367b234cbe9..f4d04eac550337b15ab17aef5ef45c0e92d6c0bc 100644 (file)
@@ -94,13 +94,19 @@ bool setPlatform(const QString &name)
     return result;
 }
 
+// 3/2024: Use a recent MSVC2022 for libclang 18.X
+static QByteArray msvcCompatVersion()
+{
+    return libClangVersion() >= QVersionNumber(0, 64) ? "19.39"_ba : "19.26"_ba;
+}
+
 static bool runProcess(const QString &program, const QStringList &arguments,
                        QByteArray *stdOutIn = nullptr, QByteArray *stdErrIn = nullptr)
 {
     QProcess process;
     process.start(program, arguments, QProcess::ReadWrite);
     if (!process.waitForStarted()) {
-        qWarning().noquote().nospace() << "Unable to start "
+        qCWarning(lcShiboken).noquote().nospace() << "Unable to start "
             << process.program() << ": " << process.errorString();
         return false;
     }
@@ -113,18 +119,18 @@ static bool runProcess(const QString &program, const QStringList &arguments,
         *stdOutIn = process.readAllStandardOutput();
 
     if (!finished) {
-        qWarning().noquote().nospace() << process.program() << " timed out: " << stdErr;
+        qCWarning(lcShiboken).noquote().nospace() << process.program() << " timed out: " << stdErr;
         process.kill();
         return false;
     }
 
     if (process.exitStatus() != QProcess::NormalExit) {
-        qWarning().noquote().nospace() << process.program() << " crashed: " << stdErr;
+        qCWarning(lcShiboken).noquote().nospace() << process.program() << " crashed: " << stdErr;
         return false;
     }
 
     if (process.exitCode() != 0) {
-        qWarning().noquote().nospace() <<  process.program() << " exited "
+        qCWarning(lcShiboken).noquote().nospace() <<  process.program() << " exited "
             << process.exitCode() << ": " << stdErr;
         return false;
     }
@@ -257,8 +263,8 @@ static QString queryLlvmConfigDir(const QString &arg)
         return {};
     const QString path = QFile::decodeName(stdOut.trimmed());
     if (!QFileInfo::exists(path)) {
-        qWarning(R"(%s: "%s" as returned by llvm-config "%s" does not exist.)",
-                 __FUNCTION__, qPrintable(QDir::toNativeSeparators(path)), qPrintable(arg));
+        qCWarning(lcShiboken, R"(%s: "%s" as returned by llvm-config "%s" does not exist.)",
+                  __FUNCTION__, qPrintable(QDir::toNativeSeparators(path)), qPrintable(arg));
         return {};
     }
     return path;
@@ -271,7 +277,8 @@ static QString findClangLibDir()
             const QString path = QFile::decodeName(qgetenv(envVar)) + u"/lib"_s;
             if (QFileInfo::exists(path))
                 return path;
-            qWarning("%s: %s as pointed to by %s does not exist.", __FUNCTION__, qPrintable(path), envVar);
+            qCWarning(lcShiboken, "%s: %s as pointed to by %s does not exist.",
+                      __FUNCTION__, qPrintable(path), envVar);
         }
     }
     return queryLlvmConfigDir(u"--libdir"_s);
@@ -283,13 +290,23 @@ static QString findClangBuiltInIncludesDir()
     const QString clangPathLibDir = findClangLibDir();
     if (!clangPathLibDir.isEmpty()) {
         QString candidate;
+        QString clangDirName = clangPathLibDir + u"/clang"_s;
+        // PYSIDE-2769: llvm-config --libdir may report /usr/lib64 on manylinux_2_28_x86_64
+        // whereas the includes are under /usr/lib/clang/../include.
+        if (!QFileInfo::exists(clangDirName) && clangPathLibDir.endsWith("64"_L1)) {
+            const QString fallback = clangPathLibDir.sliced(0, clangPathLibDir.size() - 2);
+            clangDirName = fallback + u"/clang"_s;
+            qCWarning(lcShiboken, "%s: Falling back from %s to %s.",
+                      __FUNCTION__, qPrintable(clangPathLibDir), qPrintable(fallback));
+        }
+
         QVersionNumber lastVersionNumber(1, 0, 0);
-        const QString clangDirName = clangPathLibDir + u"/clang"_s;
         QDir clangDir(clangDirName);
         const QFileInfoList versionDirs =
             clangDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
         if (versionDirs.isEmpty())
-            qWarning("%s: No subdirectories found in %s.", __FUNCTION__, qPrintable(clangDirName));
+            qCWarning(lcShiboken, "%s: No subdirectories found in %s.",
+                      __FUNCTION__, qPrintable(clangDirName));
         for (const QFileInfo &fi : versionDirs) {
             const QString fileName = fi.fileName();
             if (fileName.at(0).isDigit()) {
@@ -301,22 +318,44 @@ static QString findClangBuiltInIncludesDir()
             }
         }
         if (!candidate.isEmpty())
-            return candidate + QStringLiteral("/include");
+            return candidate + "/include"_L1;
     }
     return queryLlvmConfigDir(u"--includedir"_s);
 }
 
+QString compilerFromCMake()
+{
+#ifdef CMAKE_CXX_COMPILER
+    return QString::fromLocal8Bit(CMAKE_CXX_COMPILER);
+#else
+    return {};
+#endif
+}
+
+// Return a compiler suitable for determining the internal include paths
 static QString compilerFromCMake(const QString &defaultCompiler)
 {
     if (!compilerPath().isEmpty())
         return compilerPath();
-// Added !defined(Q_OS_DARWIN) due to PYSIDE-1032
-    QString result = defaultCompiler;
-#ifdef CMAKE_CXX_COMPILER
-    if (platform() != Platform::macOS)
-        result = QString::fromLocal8Bit(CMAKE_CXX_COMPILER);
-#endif
-    return result;
+    // Exclude macOS since cmakeCompiler returns the full path instead of the
+    // /usr/bin/clang shim, which results in the default SDK sysroot path
+    // missing (PYSIDE-1032)
+    if (platform() == Platform::macOS)
+        return defaultCompiler;
+    QString cmakeCompiler = compilerFromCMake();
+    if (cmakeCompiler.isEmpty())
+        return defaultCompiler;
+    QFileInfo fi(cmakeCompiler);
+    // Should be absolute by default, but a user may specify -DCMAKE_CXX_COMPILER=cl.exe
+    if (fi.isRelative())
+        return cmakeCompiler;
+    if (fi.exists())
+        return fi.absoluteFilePath();
+    // The compiler may not exist in case something like icecream or
+    // a non-standard-path was used on the build machine. Check
+    // the executable.
+    cmakeCompiler = QStandardPaths::findExecutable(fi.fileName());
+    return cmakeCompiler.isEmpty() ? defaultCompiler : cmakeCompiler;
 }
 
 static void appendClangBuiltinIncludes(HeaderPaths *p)
@@ -343,9 +382,10 @@ QByteArrayList emulatedCompilerOptions()
     HeaderPaths headerPaths;
     switch (compiler()) {
     case Compiler::Msvc:
-        result.append(QByteArrayLiteral("-fms-compatibility-version=19.26.28806"));
+        result.append("-fms-compatibility-version="_ba + msvcCompatVersion());
         result.append(QByteArrayLiteral("-fdelayed-template-parsing"));
         result.append(QByteArrayLiteral("-Wno-microsoft-enum-value"));
+        result.append("/Zc:__cplusplus"_ba);
         // Fix yvals_core.h:  STL1000: Unexpected compiler version, expected Clang 7 or newer (MSVC2017 update)
         result.append(QByteArrayLiteral("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH"));
         if (needsClangBuiltinIncludes())
index 18e87c4951e78c7c91aec2ca1527263d38c94934..462e8f20547531f6fcf7d569affe7eb121d3e5a9 100644 (file)
@@ -44,6 +44,8 @@ QByteArrayList detectVulkan();
 Compiler compiler();
 bool setCompiler(const QString &name);
 
+QString compilerFromCMake();
+
 const QString &compilerPath();
 void setCompilerPath(const QString &name);
 
index 2008d83d287243d504aac9b66ecb51a3c250e8ee..637e4a422dc6874fe9cf07d411b1dfe26423c270 100644 (file)
@@ -83,44 +83,51 @@ qsizetype ClassDocumentation::indexOfProperty(const QString &name) const
     return -1;
 }
 
-enum class WebXmlTag
+enum class WebXmlCodeTag
 {
-    Class, Description, Enum, Function, Parameter, Property, Typedef, Other
+    Class, Description, Enum, Function, Header, Parameter, Property, Typedef, Other
 };
 
-static WebXmlTag tag(QStringView name)
+static WebXmlCodeTag tag(QStringView name)
 {
     if (name == u"class" || name == u"namespace")
-        return WebXmlTag::Class;
+        return WebXmlCodeTag::Class;
     if (name == u"enum")
-        return WebXmlTag::Enum;
+        return WebXmlCodeTag::Enum;
     if (name == u"function")
-        return WebXmlTag::Function;
+        return WebXmlCodeTag::Function;
     if (name == u"description")
-        return WebXmlTag::Description;
+        return WebXmlCodeTag::Description;
+    if (name == u"header")
+        return WebXmlCodeTag::Header;
     if (name == u"parameter")
-        return WebXmlTag::Parameter;
+        return WebXmlCodeTag::Parameter;
     if (name == u"property")
-        return WebXmlTag::Property;
+        return WebXmlCodeTag::Property;
     if (name == u"typedef")
-        return WebXmlTag::Typedef;
-    return WebXmlTag::Other;
+        return WebXmlCodeTag::Typedef;
+    return WebXmlCodeTag::Other;
 }
 
-static void parseWebXmlElement(WebXmlTag tag, const QXmlStreamAttributes &attributes,
+static void parseWebXmlElement(WebXmlCodeTag tag, const QXmlStreamAttributes &attributes,
                                ClassDocumentation *cd)
 {
     switch (tag) {
-    case WebXmlTag::Class:
+    case WebXmlCodeTag::Class:
         cd->name = attributes.value(u"name"_s).toString();
+        cd->type = ClassDocumentation::Class;
         break;
-    case WebXmlTag::Enum: {
+    case WebXmlCodeTag::Header:
+        cd->name = attributes.value(u"name"_s).toString();
+        cd->type = ClassDocumentation::Header;
+        break;
+    case WebXmlCodeTag::Enum: {
         EnumDocumentation ed;
         ed.name = attributes.value(u"name"_s).toString();
         cd->enums.append(ed);
     }
         break;
-    case WebXmlTag::Function: {
+    case WebXmlCodeTag::Function: {
         FunctionDocumentation fd;
         fd.name = attributes.value(u"name"_s).toString();
         fd.signature = attributes.value(u"signature"_s).toString();
@@ -129,11 +136,11 @@ static void parseWebXmlElement(WebXmlTag tag, const QXmlStreamAttributes &attrib
         cd->functions.append(fd);
     }
         break;
-    case WebXmlTag::Parameter:
+    case WebXmlCodeTag::Parameter:
         Q_ASSERT(!cd->functions.isEmpty());
         cd->functions.last().parameters.append(attributes.value(u"type"_s).toString());
         break;
-    case WebXmlTag::Property: {
+    case WebXmlCodeTag::Property: {
         PropertyDocumentation pd;
         pd.name = attributes.value(u"name"_s).toString();
         pd.brief = attributes.value(u"brief"_s).toString();
@@ -185,17 +192,17 @@ static QString msgXmlError(const QString &fileName, const QXmlStreamReader &read
     return result;
 }
 
-ClassDocumentation parseWebXml(const QString &fileName, QString *errorMessage)
+std::optional<ClassDocumentation> parseWebXml(const QString &fileName, QString *errorMessage)
 {
     ClassDocumentation result;
 
     QFile file(fileName);
     if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) {
         *errorMessage = msgCannotOpenForReading(file);
-        return result;
+        return std::nullopt;
     }
 
-    WebXmlTag lastTag = WebXmlTag::Other;
+    WebXmlCodeTag lastTag = WebXmlCodeTag::Other;
     QXmlStreamReader reader(&file);
     while (!reader.atEnd()) {
         switch (reader.readNext()) {
@@ -203,26 +210,27 @@ ClassDocumentation parseWebXml(const QString &fileName, QString *errorMessage)
             const auto currentTag = tag(reader.name());
             parseWebXmlElement(currentTag, reader.attributes(), &result);
             switch (currentTag) { // Store relevant tags in lastTag
-            case WebXmlTag::Class:
-            case WebXmlTag::Function:
-            case WebXmlTag::Enum:
-            case WebXmlTag::Property:
-            case WebXmlTag::Typedef:
+            case WebXmlCodeTag::Class:
+            case WebXmlCodeTag::Function:
+            case WebXmlCodeTag::Enum:
+            case WebXmlCodeTag::Header:
+            case WebXmlCodeTag::Property:
+            case WebXmlCodeTag::Typedef:
                 lastTag = currentTag;
                 break;
-            case WebXmlTag::Description: { // Append the description to the element
+            case WebXmlCodeTag::Description: { // Append the description to the element
                 QString *target = nullptr;
                 switch (lastTag) {
-                case WebXmlTag::Class:
+                case WebXmlCodeTag::Class:
                     target = &result.description;
                     break;
-                case WebXmlTag::Function:
+                case WebXmlCodeTag::Function:
                     target = &result.functions.last().description;
                     break;
-                case WebXmlTag::Enum:
+                case WebXmlCodeTag::Enum:
                     target = &result.enums.last().description;
                     break;
-                case WebXmlTag::Property:
+                case WebXmlCodeTag::Property:
                     target = &result.properties.last().description;
                 default:
                     break;
@@ -242,7 +250,7 @@ ClassDocumentation parseWebXml(const QString &fileName, QString *errorMessage)
 
     if (reader.error() != QXmlStreamReader::NoError) {
         *errorMessage= msgXmlError(fileName, reader);
-        return {};
+        return std::nullopt;
     }
 
     sortDocumentation(&result);
@@ -363,16 +371,11 @@ QDebug operator<<(QDebug debug, const ClassDocumentation &c)
     QDebugStateSaver saver(debug);
     debug.noquote();
     debug.nospace();
-    debug << "Class(";
-    if (c) {
-        debug << c.name << ", ";
-        formatDescription(debug, c.description);
-        formatList(debug, ", enums", c.enums);
-        formatList(debug, ", properties", c.properties);
-        formatList(debug, ", functions", c.functions);
-    } else {
-        debug << "invalid";
-    }
+    debug << "Class(" << c.name << ", ";
+    formatDescription(debug, c.description);
+    formatList(debug, ", enums", c.enums);
+    formatList(debug, ", properties", c.properties);
+    formatList(debug, ", functions", c.functions);
     debug << ')';
     return debug;
 }
index ef66912f86caf357f302e5be027e271120ed687d..d47101389b0d7eff6f382e981c8b0d8efe574af2 100644 (file)
@@ -6,6 +6,8 @@
 
 #include <QtCore/QStringList>
 
+#include <optional>
+
 QT_FORWARD_DECLARE_CLASS(QDebug)
 
 /// An enumeration in a WebXML/doxygen document
@@ -41,9 +43,14 @@ struct FunctionDocumentation : public FunctionDocumentationQuery
 
 using FunctionDocumentationList = QList<FunctionDocumentation>;
 
-/// A class/namespace in a WebXML/doxygen document
+/// A WebXML/doxygen document
 struct ClassDocumentation
 {
+    enum Type {
+        Class, // <class>, class/namespace
+        Header // <header>, grouped global functions/enums
+    };
+
     qsizetype indexOfEnum(const QString &name) const;
     FunctionDocumentationList findFunctionCandidates(const QString &name,
                                                      bool constant) const;
@@ -51,18 +58,17 @@ struct ClassDocumentation
                                      const FunctionDocumentationQuery &q);
     qsizetype indexOfProperty(const QString &name) const;
 
+    Type type = Type::Class;
     QString name;
     QString description;
 
     QList<EnumDocumentation> enums;
     QList<PropertyDocumentation> properties;
     FunctionDocumentationList functions;
-
-    operator bool() const { return !name.isEmpty(); }
 };
 
 /// Parse a WebXML class/namespace document
-ClassDocumentation parseWebXml(const QString &fileName, QString *errorMessage);
+std::optional<ClassDocumentation> parseWebXml(const QString &fileName, QString *errorMessage);
 
 /// Extract the module description from a WebXML module document
 QString webXmlModuleDescription(const QString &fileName, QString *errorMessage);
index f79c68ca82de0eadd5d4470173fd8d9e4f369718..e2cd5eb35dfcadc99e643109b41ebe3707d2b6bb 100644 (file)
@@ -63,7 +63,7 @@ void CodeSnipAbstract::purgeEmptyFragments()
 
 QRegularExpression CodeSnipAbstract::placeHolderRegex(int index)
 {
-    return QRegularExpression(u'%' + QString::number(index) + QStringLiteral("\\b"));
+    return QRegularExpression(u'%' + QString::number(index) + "\\b"_L1);
 }
 
 void purgeEmptyCodeSnips(QList<CodeSnip> *list)
index ea38da7f88727ed13cb5b7204d53b4a5844d9079..5b884f2cc7be7e009c861d9a15a866dd4d1d6b4b 100644 (file)
@@ -42,7 +42,9 @@ public:
         ForceAbstract      = 0x8,
         // Indicates that the instances are used to create hierarchies
         // like widgets; parent ownership heuristics are enabled for them.
-        ParentManagement   = 0x10
+        ParentManagement   = 0x10,
+        DisableQtMetaObjectFunctions = 0x20,
+        Typedef = 0x40 // Result of a <typedef-type>
     };
     Q_DECLARE_FLAGS(TypeFlags, TypeFlag)
 
index c02a95777e01a9f59f5d33b698a15d26bcec624b..b6eda651c6502126018ceb19f4bb5329fd574208 100644 (file)
@@ -165,15 +165,15 @@ QStringList ConditionalStreamReader::platformConditions()
 {
     QStringList result;
 #if defined (Q_OS_UNIX)
-    result << QStringLiteral("unix");
+    result << "unix"_L1;
 #endif
 
 #if defined (Q_OS_LINUX)
-    result << QStringLiteral("linux");
+    result << "linux"_L1;
 #elif defined (Q_OS_MACOS)
-    result << QStringLiteral("darwin");
+    result << "darwin"_L1;
 #elif defined (Q_OS_WINDOWS)
-    result << QStringLiteral("windows");
+    result << "windows"_L1;
 #endif
     return result;
 }
index dbb09842a05cab4bed9f4858da271d2c3d98e472..468fe10981d6bf76c230802b9930aac4530ade19 100644 (file)
 
 using namespace Qt::StringLiterals;
 
-DocParser::DocParser()
+static inline bool isXpathDocModification(const DocModification &mod)
 {
-#ifdef HAVE_LIBXSLT
-    xmlSubstituteEntitiesDefault(1);
-#endif
+    return mod.mode() == TypeSystem::DocModificationXPathReplace;
 }
 
+static inline bool isNotXpathDocModification(const DocModification &mod)
+{
+    return mod.mode() != TypeSystem::DocModificationXPathReplace;
+}
+
+static void removeXpathDocModifications(DocModificationList *l)
+{
+    l->erase(std::remove_if(l->begin(), l->end(), isXpathDocModification), l->end());
+}
+
+static void removeNonXpathDocModifications(DocModificationList *l)
+{
+    l->erase(std::remove_if(l->begin(), l->end(), isNotXpathDocModification), l->end());
+}
+
+DocParser::DocParser() = default;
 DocParser::~DocParser() = default;
 
+void DocParser::fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &)
+{
+}
+
+void DocParser::fillGlobalEnumDocumentation(AbstractMetaEnum &)
+{
+}
+
 QString DocParser::getDocumentation(const XQueryPtr &xquery, const QString& query,
                                     const DocModificationList& mods)
 {
@@ -86,22 +108,59 @@ bool DocParser::skipForQuery(const AbstractMetaFunctionCPtr &func)
                        usesRValueReference);
 }
 
-DocModificationList DocParser::getDocModifications(const AbstractMetaClassCPtr &cppClass,
-                                                   const AbstractMetaFunctionCPtr &func)
+DocModificationList DocParser::getDocModifications(const AbstractMetaClassCPtr &cppClass)
+
+{
+    auto result = cppClass->typeEntry()->docModifications();
+    removeXpathDocModifications(&result);
+    return result;
+}
+
+static void filterBySignature(const AbstractMetaFunctionCPtr &func, DocModificationList *l)
 {
-    auto te = cppClass->typeEntry();
-    if (!func)
-        return te->docModifications();
+    if (!l->isEmpty()) {
+        const QString minimalSignature = func->minimalSignature();
+        const auto filter = [&minimalSignature](const DocModification &mod) {
+            return mod.signature() != minimalSignature;
+        };
+        l->erase(std::remove_if(l->begin(), l->end(), filter), l->end());
+    }
+}
 
-    if (func->isUserAdded())
-        return func->addedFunctionDocModifications();
+DocModificationList DocParser::getDocModifications(const AbstractMetaFunctionCPtr &func,
+                                                   const AbstractMetaClassCPtr &cppClass)
+{
+    DocModificationList result;
+    if (func->isUserAdded()) {
+        result = func->addedFunctionDocModifications();
+        removeXpathDocModifications(&result);
+    } else if (cppClass != nullptr) {
+        result = cppClass->typeEntry()->functionDocModifications();
+        removeXpathDocModifications(&result);
+        filterBySignature(func, &result);
+    }
+    return result;
+}
 
-    DocModificationList result = te->functionDocModifications();
-    const QString minimalSignature = func->minimalSignature();
-    const auto filter = [&minimalSignature](const DocModification &mod) {
-        return mod.signature() != minimalSignature;
-    };
-    result.erase(std::remove_if(result.begin(), result.end(), filter), result.end());
+DocModificationList DocParser::getXpathDocModifications(const AbstractMetaClassCPtr &cppClass)
+{
+    auto result = cppClass->typeEntry()->docModifications();
+    removeNonXpathDocModifications(&result);
+    return result;
+}
+
+DocModificationList DocParser::getXpathDocModifications(const AbstractMetaFunctionCPtr &func,
+                                                        const AbstractMetaClassCPtr &cppClass)
+{
+    DocModificationList result;
+    if (func->isUserAdded()) {
+        result = func->addedFunctionDocModifications();
+        removeNonXpathDocModifications(&result);
+    } else if (cppClass != nullptr) {
+        result = cppClass->typeEntry()->functionDocModifications();
+        removeNonXpathDocModifications(&result);
+        filterBySignature(func, &result);
+    }
     return result;
 }
 
@@ -131,12 +190,8 @@ AbstractMetaFunctionCList DocParser::documentableFunctions(const AbstractMetaCla
     return result;
 }
 
-static inline bool isXpathDocModification(const DocModification &mod)
-{
-    return mod.mode() == TypeSystem::DocModificationXPathReplace;
-}
-
-QString DocParser::applyDocModifications(const DocModificationList& mods, const QString& xml)
+QString DocParser::applyDocModifications(const DocModificationList& xpathMods,
+                                         const QString& xml)
 {
     const char xslPrefix[] =
 R"(<xsl:template match="/">
@@ -150,32 +205,28 @@ R"(<xsl:template match="/">
 </xsl:template>
 )";
 
-    if (mods.isEmpty() || xml.isEmpty()
-        || !std::any_of(mods.cbegin(), mods.cend(), isXpathDocModification)) {
+    if (xpathMods.isEmpty() || xml.isEmpty())
         return xml;
-    }
 
     QString xsl = QLatin1StringView(xslPrefix);
-    for (const DocModification &mod : mods) {
-        if (isXpathDocModification(mod)) {
-            QString xpath = mod.xpath();
-            xpath.replace(u'"', u"&quot;"_s);
-            xsl += u"<xsl:template match=\""_s
-                   + xpath + u"\">"_s
-                   + mod.code() + u"</xsl:template>\n"_s;
-        }
+    for (const DocModification &mod : xpathMods) {
+        Q_ASSERT(isXpathDocModification(mod));
+        QString xpath = mod.xpath();
+        xpath.replace(u'"', u"&quot;"_s);
+        xsl += "<xsl:template match=\""_L1 + xpath + "\">"_L1
+               + mod.code() + "</xsl:template>\n"_L1;
     }
 
     QString errorMessage;
     const QString result = xsl_transform(xml, xsl, &errorMessage);
     if (!errorMessage.isEmpty())
         qCWarning(lcShibokenDoc, "%s",
-                  qPrintable(msgXpathDocModificationError(mods, errorMessage)));
+                  qPrintable(msgXpathDocModificationError(xpathMods, errorMessage)));
     if (result == xml) {
         const QString message = u"Query did not result in any modifications to \""_s
             + xml + u'"';
         qCWarning(lcShibokenDoc, "%s",
-                  qPrintable(msgXpathDocModificationError(mods, message)));
+                  qPrintable(msgXpathDocModificationError(xpathMods, message)));
     }
     return result;
 }
index b5640d1d975a399ab30509af21acddc0cf079f92..6d458b25a95eb331b36e94fa15ef4dd633521738 100644 (file)
@@ -28,6 +28,8 @@ public:
     DocParser();
     virtual ~DocParser();
     virtual void fillDocumentation(const AbstractMetaClassPtr &metaClass) = 0;
+    virtual void fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &f);
+    virtual void fillGlobalEnumDocumentation(AbstractMetaEnum &e);
 
     /**
      *   Process and retrieves documentation concerning the entire
@@ -94,8 +96,12 @@ public:
 
     /// Helper to return the documentation modifications for a class
     /// or a member function.
-    static DocModificationList getDocModifications(const AbstractMetaClassCPtr &cppClass,
-                                                   const AbstractMetaFunctionCPtr &func = {});
+    static DocModificationList getDocModifications(const AbstractMetaClassCPtr &cppClass);
+    static DocModificationList getDocModifications(const AbstractMetaFunctionCPtr &func,
+                                                   const AbstractMetaClassCPtr &cppClass = {});
+    static DocModificationList getXpathDocModifications(const AbstractMetaClassCPtr &cppClass);
+    static DocModificationList getXpathDocModifications(const AbstractMetaFunctionCPtr &func,
+                                                        const AbstractMetaClassCPtr &cppClass = {});
 
     static QString enumBaseClass(const AbstractMetaEnum &e);
 
@@ -106,7 +112,7 @@ protected:
 
     static AbstractMetaFunctionCList documentableFunctions(const AbstractMetaClassCPtr &metaClass);
 
-    static QString applyDocModifications(const DocModificationList &mods, const QString &xml);
+    static QString applyDocModifications(const DocModificationList &xpathMods, const QString &xml);
 
 private:
     QString m_packageName;
index 6c4d7166eaeebf2f951cf071a94a653873bfea38..33cf0e9fb0cb696b761ef935b0618986f0e36cd8 100644 (file)
@@ -35,12 +35,6 @@ void Documentation::setFormat(Documentation::Format f)
     m_format = f;
 }
 
-bool Documentation::equals(const Documentation &rhs) const
-{
-    return m_format == rhs.m_format && m_detailed == rhs.m_detailed
-        && m_brief == rhs.m_brief;
-}
-
 void Documentation::setDetailed(const QString &detailed)
 {
     m_detailed = detailed.trimmed();
index a18bb1a13013503c415392e6cedf07058bfb76e0..df9d5d614b0afd9f4a7cf5401e9aa9d16331d239 100644 (file)
@@ -5,6 +5,7 @@
 #define DOCUMENTATION_H
 
 #include <QtCore/QString>
+#include <QtCore/QtCompare>
 
 QT_FORWARD_DECLARE_CLASS(QDebug)
 
@@ -44,16 +45,19 @@ public:
     void setBrief(const QString &brief);
 
 private:
+    friend bool comparesEqual(const Documentation &lhs,
+                              const  Documentation &rhs) noexcept
+    {
+        return lhs.m_format == rhs.m_format && lhs.m_detailed == rhs.m_detailed
+               && lhs.m_brief == rhs.m_brief;
+    }
+    Q_DECLARE_EQUALITY_COMPARABLE(Documentation)
+
     QString m_detailed;
     QString m_brief;
     Format m_format = Documentation::Native;
 };
 
-inline bool operator==(const Documentation &d1, const Documentation &d2)
-{ return d1.equals(d2); }
-inline bool operator!=(const Documentation &d1, const Documentation &d2)
-{ return !d1.equals(d2); }
-
 #ifndef QT_NO_DEBUG_STREAM
 QDebug operator<<(QDebug debug, const Documentation &);
 #endif
index da94f5e7fcd5fe4410383b25d148d71e55a17865..0bd192257ece89e4eeea304e25a5461a1af8f39f 100644 (file)
@@ -13,7 +13,7 @@ using namespace Qt::StringLiterals;
 
 bool showDotGraph(const QString &name, const QString &graph)
 {
-    const QString imageType = u"jpg"_s;
+    constexpr auto imageType = "jpg"_L1;
 
     // Write out the graph to a temporary file
     QTemporaryFile dotFile(QDir::tempPath() + u'/' + name + u"_XXXXXX.dot"_s);
@@ -43,9 +43,9 @@ bool showDotGraph(const QString &name, const QString &graph)
     // Launch image. Should use QDesktopServices::openUrl(),
     // but we don't link against QtGui
 #ifdef Q_OS_UNIX
-    const QString imageViewer = u"gwenview"_s;
+    constexpr auto imageViewer = "gwenview"_L1;
 #else
-    const QString imageViewer = u"mspaint"_s;
+    constexpr auto imageViewer = "mspaint"_L1;
 #endif
     if (!QProcess::startDetached(imageViewer, {imageFile})) {
         qWarning("Failed to launch viewer: %s", qPrintable(imageViewer));
index bcfbc39dbad12158f695d38e056e8078a83ef083..da790015fd482677e1f35032385cd5ddd72d8901 100644 (file)
@@ -54,13 +54,12 @@ void DoxygenParser::fillDocumentation(const AbstractMetaClassPtr &metaClass)
     doxyFileSuffix += metaClass->name();
     doxyFileSuffix += u".xml"_s;
 
-    const char* prefixes[] = { "class", "struct", "namespace" };
+    static constexpr QLatin1StringView prefixes[] = { "class"_L1, "struct"_L1, "namespace"_L1 };
     bool isProperty = false;
 
     QString doxyFilePath;
-    for (const char *prefix : prefixes) {
-        doxyFilePath = documentationDataDirectory() + u'/'
-                       + QLatin1StringView(prefix) + doxyFileSuffix;
+    for (const auto &prefix : prefixes) {
+        doxyFilePath = documentationDataDirectory() + u'/' + prefix + doxyFileSuffix;
         if (QFile::exists(doxyFilePath))
             break;
         doxyFilePath.clear();
@@ -151,7 +150,7 @@ void DoxygenParser::fillDocumentation(const AbstractMetaClassPtr &metaClass)
             }
 
             QString doc = getDocumentation(xquery, funcQuery,
-                                           DocParser::getDocModifications(metaClass, func));
+                                           DocParser::getXpathDocModifications(func, metaClass));
             if (doc.isEmpty()) {
                 qCWarning(lcShibokenDoc, "%s",
                           qPrintable(msgCannotFindDocumentation(doxyFilePath, func.get(),
index c7fe54d018a9cf444ff173735bcf03c26c03a6ef..3360d7db5c5ffd5b16e3ac05e2c4a0d256e643ea 100644 (file)
@@ -37,6 +37,9 @@ public:
     void addEnumValueRejection(const QString &name);
     QStringList enumValueRejections() const;
 
+    QString docFile() const;
+    void setDocFile(const QString &df);
+
     TypeEntry *clone() const override;
 #ifndef QT_NO_DEBUG_STREAM
     void formatDebug(QDebug &d) const override;
index da81f5a1bf9ce2e67f7ddafd0a4f041aed77f6bf..6f9ec4d8a378c5e91e0273d92ea18ae82ddd0689 100644 (file)
@@ -175,7 +175,7 @@ FileOut::State FileOut::done()
     if (!FileOut::m_dryRun) {
         QDir dir(info.absolutePath());
         if (!dir.mkpath(dir.absolutePath())) {
-            const QString message = QStringLiteral("Unable to create directory '%1'")
+            const QString message = QString::fromLatin1("Unable to create directory '%1'")
                                         .arg(QDir::toNativeSeparators(dir.absolutePath()));
             throw Exception(message);
         }
index 8042f950ae8bd3aab3518224099f444b355c8201..53aa1fad6d416ef855bdef48726d8e3fb1c29043 100644 (file)
@@ -19,6 +19,9 @@ public:
     bool hasSignature(const QString& signature) const;
     void addSignature(const QString& signature);
 
+    QString docFile() const;
+    void setDocFile(const QString &df);
+
     TypeEntry *clone() const override;
 
 #ifndef QT_NO_DEBUG_STREAM
index 38f6ce744c3bb1bfe4b34fb35b4dd772d59be34b..aee6b73379502cbcf85e2c3bcc624e57071a846f 100644 (file)
@@ -24,13 +24,15 @@ QString Include::toString() const
     return u"import "_s + m_name + u';';
 }
 
-int Include::compare(const Include &rhs) const
+Qt::strong_ordering compareThreeWay(const Include &lhs, const Include &rhs) noexcept
 {
-    if (m_type < rhs.m_type)
-        return -1;
-    if (m_type > rhs.m_type)
-        return 1;
-    return m_name.compare(rhs.m_name);
+    if (lhs.m_type < rhs.m_type)
+        return Qt::strong_ordering::less;
+    if (lhs.m_type > rhs.m_type)
+        return Qt::strong_ordering::greater;
+    if (auto c = lhs.m_name.compare(rhs.m_name))
+        return c < 0 ? Qt::strong_ordering::less : Qt::strong_ordering::greater;
+    return Qt::strong_ordering::equal;
 }
 
 QTextStream& operator<<(QTextStream& out, const Include& g)
index dcf8976c6655dab8616f3f8f7106b70608e01944..875a941f9149c1e9d0d9e8f62c04cb2267302be9 100644 (file)
@@ -4,6 +4,7 @@
 #ifndef INCLUDE_H
 #define INCLUDE_H
 
+#include <QtCore/QtCompare>
 #include <QtCore/QHashFunctions>
 #include <QtCore/QString>
 #include <QtCore/QList>
@@ -50,41 +51,18 @@ private:
     {
         return qHashMulti(seed, inc.m_type, inc.m_name);
     }
+    friend bool comparesEqual(const Include &lhs, const Include  &rhs) noexcept
+    {
+        return lhs.m_type == rhs.m_type && lhs.m_name == rhs.m_name;
+    }
+    friend Qt::strong_ordering compareThreeWay(const Include &lhs,
+                                               const Include &rhs) noexcept;
+    Q_DECLARE_STRONGLY_ORDERED(Include)
 
     IncludeType m_type = IncludePath;
     QString m_name;
 };
 
-inline bool operator<(const Include &lhs, const Include &rhs)
-{
-    return lhs.compare(rhs) < 0;
-}
-
-inline bool operator<=(const Include &lhs, const Include &rhs)
-{
-    return lhs.compare(rhs) <= 0;
-}
-
-inline bool operator==(const Include &lhs, const Include &rhs)
-{
-    return lhs.compare(rhs) == 0;
-}
-
-inline bool operator!=(const Include &lhs, const Include &rhs)
-{
-    return lhs.compare(rhs) != 0;
-}
-
-inline bool operator>=(const Include &lhs, const Include &rhs)
-{
-    return lhs.compare(rhs) >= 0;
-}
-
-inline bool operator>(const Include &lhs, const Include &rhs)
-{
-    return lhs.compare(rhs) > 0;
-}
-
 QTextStream& operator<<(QTextStream& out, const Include& include);
 TextStream& operator<<(TextStream& out, const Include& include);
 #ifndef QT_NO_DEBUG_STREAM
index 766b05beb878e3bed0c5f38c33c523911c3ed91c..b1f0b240e38cc56e88a78caf8e426979b53d7509 100644 (file)
@@ -26,6 +26,22 @@ using namespace Qt::StringLiterals;
 
 // abstractmetabuilder.cpp
 
+static QTextStream &operator<<(QTextStream &s, Access a)
+{
+    switch (a) {
+    case Access::Public:
+        s << "public";
+        break;
+    case Access::Protected:
+        s << "protected";
+        break;
+    case Access::Private:
+        s << "private";
+        break;
+    }
+    return s;
+}
+
 QString msgNoFunctionForModification(const AbstractMetaClassCPtr &klass,
                                      const QString &signature,
                                      const QString &originalSignature,
@@ -301,11 +317,13 @@ QString msgSkippingFunction(const FunctionModelItem &functionItem,
 {
     QString result;
     QTextStream str(&result);
-    str << functionItem->sourceLocation() << "skipping ";
-    if (functionItem->isAbstract())
+    str << functionItem->sourceLocation() << "skipping "
+        << functionItem->accessPolicy() << ' ';
+    const bool isAbstract = functionItem->attributes().testFlag(FunctionAttribute::Abstract);
+    if (isAbstract)
         str << "abstract ";
     str << "function '" << signature << "', " << why;
-    if (functionItem->isAbstract()) {
+    if (isAbstract) {
         str << "\nThis will lead to compilation errors due to not "
                "being able to instantiate the wrapper.";
     }
@@ -338,8 +356,9 @@ QString msgSkippingField(const VariableModelItem &field, const QString &classNam
 {
     QString result;
     QTextStream str(&result);
-    str << field->sourceLocation() << "skipping field '" << className
-        << "::" << field->name() << "' with unmatched type '" << type << '\'';
+    str << field->sourceLocation() << "skipping " << field->accessPolicy()
+        << " field '" << className << "::" << field->name()
+        << "' with unmatched type '" << type << '\'';
     return result;
 }
 
@@ -462,6 +481,21 @@ QString msgCannotFindTypeEntryForSmartPointer(const QString &t, const QString &s
         + u"\" for instantiation of \""_s +smartPointerType + u"\"."_s;
 }
 
+QString msgInheritTemplateIssue(const AbstractMetaClassPtr &subclass,
+                                const TypeInfo &info,
+                                const QString &what)
+{
+    return "While inheriting template "_L1 + subclass->name()
+           + " from "_L1 + info.toString() + ": "_L1 + what;
+}
+
+QString msgIgnoringTemplateParameter(const QString &typeName,
+                                     const char *why)
+{
+    return "Ignoring template parameter "_L1 + typeName +
+           ": "_L1 + QLatin1StringView(why);
+}
+
 QString msgInvalidSmartPointerType(const TypeInfo &i)
 {
     return u"Invalid smart pointer type \""_s +i.toString() + u"\"."_s;
@@ -597,9 +631,10 @@ QString msgCannotFindDocumentation(const QString &fileName,
                                    const AbstractMetaEnum &e,
                                    const QString &query)
 {
-    return msgCannotFindDocumentation(fileName, "enum",
-                                      metaClass->name() + u"::"_s + e.name(),
-                                      query);
+    QString name = e.name();
+    if (metaClass != nullptr)
+        name.prepend(metaClass->name() + "::"_L1);
+    return msgCannotFindDocumentation(fileName, "enum", name, query);
 }
 
 QString msgCannotFindDocumentation(const QString &fileName,
@@ -607,9 +642,10 @@ QString msgCannotFindDocumentation(const QString &fileName,
                                    const AbstractMetaField &f,
                                    const QString &query)
 {
-    return msgCannotFindDocumentation(fileName, "field",
-                                      metaClass->name() + u"::"_s + f.name(),
-                                      query);
+    QString name = f.name();
+    if (metaClass != nullptr)
+        name.prepend(metaClass->name() + "::"_L1);
+    return msgCannotFindDocumentation(fileName, "field", name, query);
 }
 
 QString msgXpathDocModificationError(const DocModificationList& mods,
@@ -637,13 +673,13 @@ QString msgXpathDocModificationError(const DocModificationList& mods,
 
 QString msgCannotOpenForReading(const QFile &f)
 {
-    return QStringLiteral("Failed to open file '%1' for reading: %2")
+    return QString::fromLatin1("Failed to open file '%1' for reading: %2")
            .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
 }
 
 QString msgCannotOpenForWriting(const QFile &f)
 {
-    return QStringLiteral("Failed to open file '%1' for writing: %2")
+    return QString::fromLatin1("Failed to open file '%1' for writing: %2")
            .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
 }
 
index 2899cbdfa232a12743c074fa77fdaab15e9fe6d3..e3f582b492cdf827fcfeb0e03dfd70c95b78e1e9 100644 (file)
@@ -126,6 +126,10 @@ QString msgUnableToTranslateType(const TypeInfo &typeInfo,
 QString msgCannotFindTypeEntry(const QString &t);
 
 QString msgCannotFindTypeEntryForSmartPointer(const QString &t, const QString &smartPointerType);
+QString msgInheritTemplateIssue(const AbstractMetaClassPtr &subclass,
+                                const TypeInfo &info, const QString &what);
+QString msgIgnoringTemplateParameter(const QString &typeName,
+                                     const char *why);
 QString msgInvalidSmartPointerType(const TypeInfo &i);
 QString msgCannotFindSmartPointerInstantion(const TypeInfo &i);
 
index 4e08d85608ee762b84db78e8e4ef9ff2d46020ec..d876e8035463bd23beadc59476a130c58d0db047 100644 (file)
 
 using namespace Qt::StringLiterals;
 
-// ---------------------- Modification
-QString FunctionModification::accessModifierString() const
-{
-    if (isPrivate())
-        return u"private"_s;
-    if (isProtected())
-        return u"protected"_s;
-    if (isPublic())
-        return u"public"_s;
-    if (isFriendly())
-        return u"friendly"_s;
-    return {};
-}
-
 // ---------------------- FieldModification
 
 class FieldModificationData : public QSharedData
index 3763f6154969f8a6151bbd36674e3f97f7a9f3e3..27a38f1aa8e0460640d6d0d890ef92c38a5c786a 100644 (file)
@@ -141,8 +141,7 @@ public:
     enum ModifierFlag {
         Private =               0x0001,
         Protected =             0x0002,
-        Public =                0x0003,
-        Friendly =              0x0004,
+        Public =                0x0004,
         AccessModifierMask =    0x000f,
 
         Final =                 0x0010,
@@ -191,10 +190,6 @@ public:
     {
         return accessModifier() == Public;
     }
-    bool isFriendly() const
-    {
-        return accessModifier() == Friendly;
-    }
     bool isFinal() const
     {
         return modifiers().testFlag(Final);
@@ -203,7 +198,6 @@ public:
     {
         return modifiers().testFlag(NonFinal);
     }
-    QString accessModifierString() const;
 
     bool isDeprecated() const
     {
index cf8403d596af8c2f1a841312202556a1c19ef7db..259a706dc9ff41a53624960676d8afd27789ee2c 100644 (file)
 #include <QtCore/QRegularExpression>
 
 #include <algorithm>
-#include <functional>
-#include <iostream>
 
 using namespace Qt::StringLiterals;
 
-// Predicate to find an item by name in a list of std::shared_ptr<Item>
-template <class T> class ModelItemNamePredicate
-{
-public:
-    explicit ModelItemNamePredicate(const QString &name) : m_name(name) {}
-    bool operator()(const std::shared_ptr<T> &item) const { return item->name() == m_name; }
-
-private:
-    const QString m_name;
-};
-
 template <class T>
-static std::shared_ptr<T> findModelItem(const QList<std::shared_ptr<T> > &list, const QString &name)
+static std::shared_ptr<T> findModelItem(const QList<std::shared_ptr<T> > &list,
+                                        QAnyStringView name)
 {
-    const auto it = std::find_if(list.cbegin(), list.cend(), ModelItemNamePredicate<T>(name));
-    return it != list.cend() ? *it : std::shared_ptr<T>();
+    using ItemPtr = std::shared_ptr<T>;
+    auto pred = [name](const ItemPtr &item) { return item->name() == name; };
+    const auto it = std::find_if(list.cbegin(), list.cend(), pred);
+    return it != list.cend() ? *it : ItemPtr{};
 }
 
 // ---------------------------------------------------------------------------
@@ -54,7 +44,7 @@ void CodeModel::addFile(const FileModelItem &item)
     m_files.append(item);
 }
 
-FileModelItem CodeModel::findFile(const QString &name) const
+FileModelItem CodeModel::findFile(QAnyStringView name) const
 {
     return findModelItem(m_files, name);
 }
@@ -628,52 +618,46 @@ void  _ScopeModelItem::formatDebug(QDebug &d) const
 }
 #endif // !QT_NO_DEBUG_STREAM
 
-namespace {
 // Predicate to match a non-template class name against the class list.
 // "Vector" should match "Vector" as well as "Vector<T>" (as seen for methods
 // from within the class "Vector").
-class ClassNamePredicate
+static bool matchClassNameNonTemplatePart(const ClassModelItem &item, const QString &name)
 {
-public:
-    explicit ClassNamePredicate(const QString &name) : m_name(name) {}
-    bool operator()(const ClassModelItem &item) const
-    {
-        const QString &itemName = item->name();
-        if (!itemName.startsWith(m_name))
-            return false;
-        return itemName.size() == m_name.size() || itemName.at(m_name.size()) == u'<';
-    }
-
-private:
-    const QString m_name;
-};
-} // namespace
+    const QString &itemName = item->name();
+    if (!itemName.startsWith(name))
+        return false;
+    return itemName.size() == name.size() || itemName.at(name.size()) == u'<';
+}
 
 ClassModelItem _ScopeModelItem::findClass(const QString &name) const
 {
     // A fully qualified template is matched by name only
     const ClassList::const_iterator it = name.contains(u'<')
-        ? std::find_if(m_classes.begin(), m_classes.end(), ModelItemNamePredicate<_ClassModelItem>(name))
-        : std::find_if(m_classes.begin(), m_classes.end(), ClassNamePredicate(name));
+        ? std::find_if(m_classes.begin(), m_classes.end(),
+                       [&name](const ClassModelItem &item) {
+                               return item->name() == name; })
+        : std::find_if(m_classes.begin(), m_classes.end(),
+                       [&name](const ClassModelItem &item) {
+                               return matchClassNameNonTemplatePart(item, name); });
     return it != m_classes.end() ? *it : ClassModelItem();
 }
 
-VariableModelItem _ScopeModelItem::findVariable(const QString &name) const
+VariableModelItem _ScopeModelItem::findVariable(QAnyStringView name) const
 {
     return findModelItem(m_variables, name);
 }
 
-TypeDefModelItem _ScopeModelItem::findTypeDef(const QString &name) const
+TypeDefModelItem _ScopeModelItem::findTypeDef(QAnyStringView name) const
 {
     return findModelItem(m_typeDefs, name);
 }
 
-TemplateTypeAliasModelItem _ScopeModelItem::findTemplateTypeAlias(const QString &name) const
+TemplateTypeAliasModelItem _ScopeModelItem::findTemplateTypeAlias(QAnyStringView name) const
 {
     return findModelItem(m_templateTypeAliases, name);
 }
 
-EnumModelItem _ScopeModelItem::findEnum(const QString &name) const
+EnumModelItem _ScopeModelItem::findEnum(QAnyStringView name) const
 {
     return findModelItem(m_enums, name);
 }
@@ -762,7 +746,7 @@ _ScopeModelItem::FindEnumByValueReturn
     return findEnumByValueRecursion(this, value, enumValue);
 }
 
-FunctionList _ScopeModelItem::findFunctions(const QString &name) const
+FunctionList _ScopeModelItem::findFunctions(QAnyStringView name) const
 {
     FunctionList result;
     for (const FunctionModelItem &func : m_functions) {
@@ -791,7 +775,7 @@ void _NamespaceModelItem::addNamespace(NamespaceModelItem item)
     m_namespaces.append(item);
 }
 
-NamespaceModelItem _NamespaceModelItem::findNamespace(const QString &name) const
+NamespaceModelItem _NamespaceModelItem::findNamespace(QAnyStringView name) const
 {
     return findModelItem(m_namespaces, name);
 }
@@ -1018,66 +1002,16 @@ void _FunctionModelItem::setDeleted(bool d)
     m_isDeleted = d;
 }
 
-bool _FunctionModelItem::isDeprecated() const
-{
-    return m_isDeprecated;
-}
-
-void _FunctionModelItem::setDeprecated(bool d)
-{
-    m_isDeprecated = d;
-}
-
-bool _FunctionModelItem::isVirtual() const
-{
-    return m_isVirtual;
-}
-
-void _FunctionModelItem::setVirtual(bool isVirtual)
-{
-    m_isVirtual = isVirtual;
-}
-
 bool _FunctionModelItem::isInline() const
 {
     return m_isInline;
 }
 
-bool _FunctionModelItem::isOverride() const
-{
-    return m_isOverride;
-}
-
-void _FunctionModelItem::setOverride(bool o)
-{
-    m_isOverride = o;
-}
-
-bool _FunctionModelItem::isFinal() const
-{
-    return m_isFinal;
-}
-
-void _FunctionModelItem::setFinal(bool f)
-{
-    m_isFinal = f;
-}
-
 void _FunctionModelItem::setInline(bool isInline)
 {
     m_isInline = isInline;
 }
 
-bool _FunctionModelItem::isExplicit() const
-{
-    return m_isExplicit;
-}
-
-void _FunctionModelItem::setExplicit(bool isExplicit)
-{
-    m_isExplicit = isExplicit;
-}
-
 bool _FunctionModelItem::isHiddenFriend() const
 {
     return m_isHiddenFriend;
@@ -1088,27 +1022,6 @@ void _FunctionModelItem::setHiddenFriend(bool f)
     m_isHiddenFriend = f;
 }
 
-bool _FunctionModelItem::isAbstract() const
-{
-    return m_isAbstract;
-}
-
-void _FunctionModelItem::setAbstract(bool isAbstract)
-{
-    m_isAbstract = isAbstract;
-}
-
-// Qt
-bool _FunctionModelItem::isInvokable() const
-{
-    return m_isInvokable;
-}
-
-void _FunctionModelItem::setInvokable(bool isInvokable)
-{
-    m_isInvokable = isInvokable;
-}
-
 QString _FunctionModelItem::typeSystemSignature() const  // For dumping out type system files
 {
     QString result;
@@ -1233,17 +1146,17 @@ void _FunctionModelItem::formatDebug(QDebug &d) const
         d << " [deleted!]";
     if (m_isInline)
         d << " [inline]";
-    if (m_isVirtual)
+    if (m_attributes.testFlag(FunctionAttribute::Virtual))
         d << " [virtual]";
-    if (m_isOverride)
+    if (m_attributes.testFlag(FunctionAttribute::Override))
         d << " [override]";
-    if (m_isDeprecated)
+    if (m_attributes.testFlag(FunctionAttribute::Deprecated))
         d << " [deprecated]";
-    if (m_isFinal)
+    if (m_attributes.testFlag(FunctionAttribute::Final))
         d << " [final]";
-    if (m_isAbstract)
+    if (m_attributes.testFlag(FunctionAttribute::Abstract))
         d << " [abstract]";
-    if (m_isExplicit)
+    if (m_attributes.testFlag(FunctionAttribute::Explicit))
         d << " [explicit]";
     if (m_isInvokable)
         d << " [invokable]";
index 3ebc44c273960b7c4d6fd6b0e149303d1e468cbf..b31c09163a41995cab33c43c4b9beeebcb38d8be 100644 (file)
@@ -74,7 +74,7 @@ public:
     NamespaceModelItem globalNamespace() const;
 
     void addFile(const FileModelItem &item);
-    FileModelItem findFile(const QString &name) const;
+    FileModelItem findFile(QAnyStringView name) const;
 
     static CodeModelItem findItem(const QStringList &qualifiedName,
                                   const ScopeModelItem &scope);
@@ -196,7 +196,7 @@ public:
     void addVariable(const VariableModelItem &item);
 
     ClassModelItem findClass(const QString &name) const;
-    EnumModelItem findEnum(const QString &name) const;
+    EnumModelItem findEnum(QAnyStringView name) const;
 
     struct FindEnumByValueReturn
     {
@@ -207,10 +207,10 @@ public:
     };
     FindEnumByValueReturn findEnumByValue(QStringView value) const;
 
-    FunctionList findFunctions(const QString &name) const;
-    TypeDefModelItem findTypeDef(const QString &name) const;
-    TemplateTypeAliasModelItem findTemplateTypeAlias(const QString &name) const;
-    VariableModelItem findVariable(const QString &name) const;
+    FunctionList findFunctions(QAnyStringView name) const;
+    TypeDefModelItem findTypeDef(QAnyStringView name) const;
+    TemplateTypeAliasModelItem findTemplateTypeAlias(QAnyStringView name) const;
+    VariableModelItem findVariable(QAnyStringView name) const;
 
     void addEnumsDeclaration(const QString &enumsDeclaration);
     QStringList enumsDeclarations() const { return m_enumsDeclarations; }
@@ -338,7 +338,7 @@ public:
 
     void addNamespace(NamespaceModelItem item);
 
-    NamespaceModelItem findNamespace(const QString &name) const;
+    NamespaceModelItem findNamespace(QAnyStringView name) const;
 
     void appendNamespace(const _NamespaceModelItem &other);
 
@@ -485,36 +485,19 @@ public:
 
     static std::optional<CodeModel::FunctionType> functionTypeFromName(QStringView name);
 
+    FunctionAttributes attributes() const { return m_attributes; }
+    void setAttributes(FunctionAttributes a) { m_attributes = a; }
+    void setAttribute(FunctionAttribute a, bool on = true) { m_attributes.setFlag(a, on); }
+
     bool isDeleted() const;
     void setDeleted(bool d);
 
-    bool isDeprecated() const;
-    void setDeprecated(bool d);
-
-    bool isVirtual() const;
-    void setVirtual(bool isVirtual);
-
-    bool isOverride() const;
-    void setOverride(bool o);
-
-    bool isFinal() const;
-    void setFinal(bool f);
-
     bool isInline() const;
     void setInline(bool isInline);
 
-    bool isExplicit() const;
-    void setExplicit(bool isExplicit);
-
     bool isHiddenFriend() const;
     void setHiddenFriend(bool f);
 
-    bool isInvokable() const; // Qt
-    void setInvokable(bool isInvokable); // Qt
-
-    bool isAbstract() const;
-    void setAbstract(bool isAbstract);
-
     bool isVariadics() const;
     void setVariadics(bool isVariadics);
 
@@ -546,17 +529,12 @@ private:
     CodeModel::FunctionType _determineTypeHelper() const;
 
     ArgumentList m_arguments;
+    FunctionAttributes m_attributes;
     CodeModel::FunctionType m_functionType = CodeModel::Normal;
     union {
         struct {
             uint m_isDeleted: 1;
-            uint m_isVirtual: 1;
-            uint m_isOverride: 1;
-            uint m_isFinal: 1;
-            uint m_isDeprecated: 1;
             uint m_isInline: 1;
-            uint m_isAbstract: 1;
-            uint m_isExplicit: 1;
             uint m_isVariadics: 1;
             uint m_isHiddenFriend: 1;
             uint m_isInvokable : 1; // Qt
index 1a058bdfe8bbfc2367947eea3e5a105be4f44e52..e5c429bd0d58b63f4998c8b0c04be57dddaa958a 100644 (file)
@@ -4,6 +4,8 @@
 #ifndef CODEMODEL_ENUMS_H
 #define CODEMODEL_ENUMS_H
 
+#include <QtCore/qflags.h>
+
 enum ReferenceType {
     NoReference,
     LValueReference,
@@ -43,4 +45,17 @@ enum class Access
     Public
 };
 
+enum class FunctionAttribute {
+    Abstract   = 0x00000001,
+    Static     = 0x00000002,
+    Virtual    = 0x00000004,
+    Override   = 0x00000008,
+    Final      = 0x00000010,
+    Deprecated = 0x00000020, // Code annotation
+    Explicit   = 0x00000040, // Constructor
+};
+
+Q_DECLARE_FLAGS(FunctionAttributes, FunctionAttribute)
+Q_DECLARE_OPERATORS_FOR_FLAGS(FunctionAttributes)
+
 #endif // CODEMODEL_ENUMS_H
index 09c34cb91b9e597e0c4e951e90cd948c54a6f142..3749e16a8b31b9868281be8cd4f65e95afac2e91 100644 (file)
@@ -56,11 +56,12 @@ EnumValue EnumValue::toUnsigned() const
     return result;
 }
 
-bool EnumValue::equals(const EnumValue &rhs) const
+bool comparesEqual(const EnumValue &lhs, const EnumValue &rhs) noexcept
 {
-    if (m_type != rhs.m_type)
+    if (lhs.m_type != rhs.m_type)
         return false;
-    return m_type == Signed ? m_value == rhs.m_value : m_unsignedValue == rhs.m_unsignedValue;
+    return lhs.m_type == EnumValue::Signed
+        ? lhs.m_value == rhs.m_value : lhs.m_unsignedValue == rhs.m_unsignedValue;
 }
 
 void EnumValue::formatDebugHex(QDebug &d) const
index 053a97a05c6b9a2b354c36ab092d0a7fd7209961..bbd5a712d3c04a077704972e81eecb65245b8492 100644 (file)
@@ -4,7 +4,9 @@
 #ifndef ENUMVALUE_H
 #define ENUMVALUE_H
 
-#include <QtCore/QtGlobal>
+#include <QtCore/qtypes.h>
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/QtCompare>
 
 QT_FORWARD_DECLARE_CLASS(QDebug)
 QT_FORWARD_DECLARE_CLASS(QString)
@@ -39,6 +41,10 @@ public:
     void formatDebugHex(QDebug &d) const;
 
 private:
+    friend bool comparesEqual(const EnumValue &lhs,
+                              const EnumValue &rhs) noexcept;
+    Q_DECLARE_EQUALITY_COMPARABLE(EnumValue)
+
 #ifndef QT_NO_DEBUG_STREAM
     friend QDebug operator<<(QDebug, const EnumValue &);
 #endif
@@ -52,9 +58,4 @@ private:
     Type m_type = Signed;
 };
 
-inline bool operator==(const EnumValue &e1, const EnumValue &e2)
-{ return e1.equals(e2); }
-inline bool operator!=(const EnumValue &e1, const EnumValue &e2)
-{ return !e1.equals(e2); }
-
 #endif // ENUMVALUE_H
index 5fa9374ed92d74ac5b87d58564403525f7fa8949..f8c5c31d82f73c9989ab7d5c415b9730cfc914be 100644 (file)
@@ -266,6 +266,12 @@ void TypeInfo::clearInstantiations()
         d->m_instantiations.clear();
 }
 
+bool TypeInfo::isPlain() const
+{
+    return d->m_constant == 0 && d->m_volatile == 0 && d->m_referenceType == NoReference
+        &&  d->m_indirections.isEmpty() && d->m_arrayElements.isEmpty();
+}
+
 TypeInfo TypeInfo::resolveType(TypeInfo const &__type, const ScopeModelItem &__scope)
 {
     CodeModel *__model = __scope->model();
@@ -446,31 +452,28 @@ bool TypeInfoData::equals(const TypeInfoData &other) const
            && m_instantiations == other.m_instantiations;
 }
 
-bool TypeInfo::equals(const TypeInfo &other) const
+
+bool comparesEqual(const TypeInfo &lhs, const TypeInfo &rhs) noexcept
 {
-    return d.data() == other.d.data() || d->equals(*other.d);
+   return lhs.d.data() == rhs.d.data() || lhs.d->equals(*rhs.d);
 }
 
 QString TypeInfo::indirectionKeyword(Indirection i)
 {
-    return i == Indirection::Pointer
-        ? QStringLiteral("*") : QStringLiteral("*const");
+    return i == Indirection::Pointer ? "*"_L1 : "*const"_L1;
 }
 
-static inline QString constQualifier() { return QStringLiteral("const"); }
-static inline QString volatileQualifier() { return QStringLiteral("volatile"); }
-
 bool TypeInfo::stripLeadingConst(QString *s)
 {
-    return stripLeadingQualifier(constQualifier(), s);
+    return stripLeadingQualifier("const"_L1, s);
 }
 
 bool TypeInfo::stripLeadingVolatile(QString *s)
 {
-    return stripLeadingQualifier(volatileQualifier(), s);
+    return stripLeadingQualifier("volatile"_L1, s);
 }
 
-bool TypeInfo::stripLeadingQualifier(const QString &qualifier, QString *s)
+bool TypeInfo::stripLeadingQualifier(QLatin1StringView qualifier, QString *s)
 {
     // "const int x"
     const auto qualifierSize = qualifier.size();
index 0f1a04f6f168010278ee224a1dc2c7ea0243be8b..e4f363b679b10e580e66e23e4d03009944f72fa4 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <QtCore/QString>
 #include <QtCore/QSharedDataPointer>
+#include <QtCore/QtCompare>
 #include <QtCore/QStringList>
 
 #include <utility>
@@ -79,13 +80,13 @@ public:
     void addInstantiation(const TypeInfo &i);
     void clearInstantiations();
 
+    bool isPlain() const; // neither const,volatile, no indirections/references, array
+
     bool isStdType() const;
 
     std::pair<qsizetype, qsizetype>
         parseTemplateArgumentList(const QString &l, qsizetype from = 0);
 
-    bool equals(const TypeInfo &other) const;
-
     // ### arrays and templates??
 
     QString toString() const;
@@ -103,12 +104,16 @@ public:
 
     static bool stripLeadingConst(QString *s);
     static bool stripLeadingVolatile(QString *s);
-    static bool stripLeadingQualifier(const QString &qualifier, QString *s);
+    static bool stripLeadingQualifier(QLatin1StringView qualifier, QString *s);
     static void stripQualifiers(QString *s);
 
     void simplifyStdType();
 
 private:
+    friend bool comparesEqual(const TypeInfo &lhs,
+                              const TypeInfo &rhs) noexcept;
+    Q_DECLARE_EQUALITY_COMPARABLE(TypeInfo)
+
     QSharedDataPointer<TypeInfoData> d;
 
     friend class TypeInfoTemplateArgumentHandler;
@@ -116,12 +121,6 @@ private:
     static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, const ScopeModelItem &__scope);
 };
 
-inline bool operator==(const TypeInfo &t1, const TypeInfo &t2)
-{ return t1.equals(t2); }
-
-inline bool operator!=(const TypeInfo &t1, const TypeInfo &t2)
-{ return !t1.equals(t2); }
-
 #ifndef QT_NO_DEBUG_STREAM
 QDebug operator<<(QDebug d, const TypeInfo &t);
 #endif
index 7ff7c26e2e524cb8c8e7e8ff6644c6855f7ab135..992f735ac22253df0fa7475f84b96e9bef8b2682 100644 (file)
@@ -56,20 +56,20 @@ for (auto oit = std::begin(%out), oend = std::end(%out); oit != oend; ++oit) {
 )"_s;
 }
 
-static const char stlMapKeyAccessor[] = "->first";
-static const char stlMapValueAccessor[] = "->second";
-static const char qtMapKeyAccessor[] = ".key()";
-static const char qtMapValueAccessor[] = ".value()";
+static constexpr auto stlMapKeyAccessor = "->first"_L1;
+static constexpr auto stlMapValueAccessor = "->second"_L1;
+static constexpr auto qtMapKeyAccessor = ".key()"_L1;
+static constexpr auto qtMapValueAccessor = ".value()"_L1;
 
 static QString cppMapToPyDict(bool isQMap)
 {
     return uR"(PyObject *%out = PyDict_New();
 for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ++it) {
     const auto &key = it)"_s
-        + QLatin1StringView(isQMap ? qtMapKeyAccessor : stlMapKeyAccessor)
+        + (isQMap ? qtMapKeyAccessor : stlMapKeyAccessor)
         + uR"(;
     const auto &value = it)"_s
-        + QLatin1StringView(isQMap ? qtMapValueAccessor : stlMapValueAccessor)
+        + (isQMap ? qtMapValueAccessor : stlMapValueAccessor)
         + uR"(;
     PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
     PyObject *pyValue = %CONVERTTOPYTHON[%INTYPE_1](value);
@@ -103,7 +103,7 @@ static QString cppMultiMapToPyDict(bool isQMultiMap)
     return uR"(PyObject *%out = PyDict_New();
     for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ) {
         const auto &key = it)"_s
-        + QLatin1StringView(isQMultiMap ? qtMapKeyAccessor : stlMapKeyAccessor)
+        + (isQMultiMap ? qtMapKeyAccessor : stlMapKeyAccessor)
         + uR"(;
         PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
         auto upper = %in.)"_s
@@ -129,7 +129,7 @@ static QString cppMultiHashToPyDict(bool isQMultiHash)
     return uR"(PyObject *%out = PyDict_New();
     for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ) {
         const auto &key = it)"_s
-           +  QLatin1StringView(isQMultiHash ? qtMapKeyAccessor : stlMapKeyAccessor)
+           + (isQMultiHash ? qtMapKeyAccessor : stlMapKeyAccessor)
            + uR"(;
         PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
         auto range = %in.equal_range(key);
index c676d3cf32abb061f7dd81005acff65fc845c1c5..34cdd74a9fc33e6cca7f865f594b241278d5955c 100644 (file)
@@ -192,11 +192,11 @@ TypeSystemProperty QPropertySpec::typeSystemPropertyFromQ_Property(const QString
     enum class PropertyToken { None, Read, Write, Designable, Reset, Notify };
 
     static const QHash<QString, PropertyToken> tokenLookup = {
-        {QStringLiteral("READ"), PropertyToken::Read},
-        {QStringLiteral("WRITE"), PropertyToken::Write},
-        {QStringLiteral("DESIGNABLE"), PropertyToken::Designable},
-        {QStringLiteral("RESET"), PropertyToken::Reset},
-        {QStringLiteral("NOTIFY"), PropertyToken::Notify}
+        {"READ"_L1, PropertyToken::Read},
+        {"WRITE"_L1, PropertyToken::Write},
+        {"DESIGNABLE"_L1, PropertyToken::Designable},
+        {"RESET"_L1, PropertyToken::Reset},
+        {"NOTIFY"_L1, PropertyToken::Notify}
     };
 
     errorMessage->clear();
index 4a716ba594b612305594c6495dd1d7015d9f2a4c..a8694eb3016f52fdb1590d4858e692ef2fd2312a 100644 (file)
@@ -13,10 +13,10 @@ class TextStream;
 
 struct castToPyCFunction
 {
-    explicit castToPyCFunction(QStringView function) noexcept :
+    explicit castToPyCFunction(QAnyStringView function) noexcept :
         m_function(function) {}
 
-    QStringView m_function;
+    QAnyStringView m_function;
 };
 
 struct PyMethodDefEntry
index 9627bb76cc345ef5ff23bf855eecc104156456a4..3837dcfd2bc62a0856d442de932708ecb71e05a2 100644 (file)
@@ -4,7 +4,7 @@
 #ifndef QTCOMPAT_H
 #define QTCOMPAT_H
 
-#include <QtCore/QtGlobal>
+#include <QtCore/qtconfigmacros.h>
 
 #if QT_VERSION < 0x060400
 
index badf6b7af7bbc3272dbb43248ac5a91a8280f223..5bd99bbd8cbf6346ae307f7c252b40a2c73131d8 100644 (file)
@@ -15,6 +15,8 @@
 #include "reporthandler.h"
 #include "flagstypeentry.h"
 #include "complextypeentry.h"
+#include "functiontypeentry.h"
+#include "enumtypeentry.h"
 
 #include "qtcompat.h"
 
@@ -26,8 +28,9 @@ using namespace Qt::StringLiterals;
 
 enum { debugFunctionSearch = 0 };
 
-static inline QString briefStartElement() { return QStringLiteral("<brief>"); }
-static inline QString briefEndElement() { return QStringLiteral("</brief>"); }
+constexpr auto briefStartElement = "<brief>"_L1;
+constexpr auto briefEndElement = "</brief>"_L1;
+constexpr auto webxmlSuffix = ".webxml"_L1;
 
 Documentation QtDocParser::retrieveModuleDocumentation()
 {
@@ -112,7 +115,7 @@ QString QtDocParser::functionDocumentation(const QString &sourceFileName,
         queryFunctionDocumentation(sourceFileName, classDocumentation, metaClass,
                                    func, errorMessage);
 
-    const auto funcModifs = DocParser::getDocModifications(metaClass, func);
+    const auto funcModifs = DocParser::getXpathDocModifications(func, metaClass);
     return docString.isEmpty() || funcModifs.isEmpty()
         ? docString : applyDocModifications(funcModifs, docString);
 }
@@ -187,21 +190,92 @@ QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName,
 // from the source.
 static QString extractBrief(QString *value)
 {
-    const auto briefStart = value->indexOf(briefStartElement());
+    const auto briefStart = value->indexOf(briefStartElement);
     if (briefStart < 0)
         return {};
-    const auto briefEnd = value->indexOf(briefEndElement(),
-                                         briefStart + briefStartElement().size());
+    const auto briefEnd = value->indexOf(briefEndElement,
+                                         briefStart + briefStartElement.size());
     if (briefEnd < briefStart)
         return {};
-    const auto briefLength = briefEnd + briefEndElement().size() - briefStart;
+    const auto briefLength = briefEnd + briefEndElement.size() - briefStart;
     QString briefValue = value->mid(briefStart, briefLength);
-    briefValue.insert(briefValue.size() - briefEndElement().size(),
+    briefValue.insert(briefValue.size() - briefEndElement.size(),
                       u"<rst> More_...</rst>"_s);
     value->remove(briefStart, briefLength);
     return briefValue;
 }
 
+// Find the webxml file for global functions/enums
+// by the doc-file typesystem attribute or via include file.
+static QString findGlobalWebXmLFile(const QString &documentationDataDirectory,
+                                    const QString &docFile,
+                                    const Include &include)
+{
+    QString result;
+    if (!docFile.isEmpty()) {
+        result = documentationDataDirectory + u'/' + docFile;
+        if (!result.endsWith(webxmlSuffix))
+            result += webxmlSuffix;
+        return QFileInfo::exists(result) ? result : QString{};
+    }
+    if (include.name().isEmpty())
+        return {};
+    // qdoc "\headerfile <QtLogging>" directive produces "qtlogging.webxml"
+    result = documentationDataDirectory + u'/' +
+             QFileInfo(include.name()).baseName() + webxmlSuffix;
+    if (QFileInfo::exists(result))
+        return result;
+    // qdoc "\headerfile <qdrawutil.h>" produces "qdrawutil-h.webxml"
+    result.insert(result.size() - webxmlSuffix.size(), "-h"_L1);
+    return QFileInfo::exists(result) ? result : QString{};
+}
+
+void  QtDocParser::fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &f)
+{
+    auto te = f->typeEntry();
+    if (te == nullptr)
+        return;
+
+    const QString sourceFileName =
+        findGlobalWebXmLFile(documentationDataDirectory(), te->docFile(), te->include());
+    if (sourceFileName.isEmpty())
+        return;
+
+    QString errorMessage;
+    auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage);
+    if (!classDocumentationO.has_value()) {
+        qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+        return;
+    }
+    const QString detailed =
+        functionDocumentation(sourceFileName, classDocumentationO.value(),
+                              {}, f, &errorMessage);
+    if (!errorMessage.isEmpty())
+        qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+    const Documentation documentation(detailed, {});
+    f->setDocumentation(documentation);
+}
+
+void QtDocParser::fillGlobalEnumDocumentation(AbstractMetaEnum &e)
+{
+    auto te = e.typeEntry();
+    const QString sourceFileName =
+        findGlobalWebXmLFile(documentationDataDirectory(), te->docFile(), te->include());
+    if (sourceFileName.isEmpty())
+        return;
+
+    QString errorMessage;
+    auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage);
+    if (!classDocumentationO.has_value()) {
+        qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
+        return;
+    }
+    if (!extractEnumDocumentation(classDocumentationO.value(), e)) {
+        qCWarning(lcShibokenDoc, "%s",
+                  qPrintable(msgCannotFindDocumentation(sourceFileName, {}, e, {})));
+    }
+}
+
 void QtDocParser::fillDocumentation(const AbstractMetaClassPtr &metaClass)
 {
     if (!metaClass)
@@ -218,9 +292,9 @@ void QtDocParser::fillDocumentation(const AbstractMetaClassPtr &metaClass)
         + metaClass->qualifiedCppName().toLower();
     sourceFileRoot.replace(u"::"_s, u"-"_s);
 
-    QFileInfo sourceFile(sourceFileRoot + QStringLiteral(".webxml"));
+    QFileInfo sourceFile(sourceFileRoot + webxmlSuffix);
     if (!sourceFile.exists())
-        sourceFile.setFile(sourceFileRoot + QStringLiteral(".xml"));
+        sourceFile.setFile(sourceFileRoot + ".xml"_L1);
    if (!sourceFile.exists()) {
         qCWarning(lcShibokenDoc).noquote().nospace()
             << "Can't find qdoc file for class " << metaClass->name() << ", tried: "
@@ -231,18 +305,19 @@ void QtDocParser::fillDocumentation(const AbstractMetaClassPtr &metaClass)
     const QString sourceFileName = sourceFile.absoluteFilePath();
     QString errorMessage;
 
-    const ClassDocumentation classDocumentation = parseWebXml(sourceFileName, &errorMessage);
-    if (!classDocumentation) {
+    const auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage);
+    if (!classDocumentationO.has_value()) {
         qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage));
         return;
     }
 
+    const auto &classDocumentation = classDocumentationO.value();
     for (const auto &p : classDocumentation.properties) {
         Documentation doc(p.description, p.brief);
         metaClass->setPropertyDocumentation(p.name, doc);
     }
 
-    QString docString = applyDocModifications(metaClass->typeEntry()->docModifications(),
+    QString docString = applyDocModifications(DocParser::getXpathDocModifications(metaClass),
                                               classDocumentation.description);
 
     if (docString.isEmpty()) {
@@ -283,28 +358,35 @@ void QtDocParser::fillDocumentation(const AbstractMetaClassPtr &metaClass)
 #endif
     // Enums
     for (AbstractMetaEnum &meta_enum : metaClass->enums()) {
-        Documentation enumDoc;
-        const auto index = classDocumentation.indexOfEnum(meta_enum.name());
-        if (index != -1) {
-            QString doc = classDocumentation.enums.at(index).description;
-            const auto firstPara = doc.indexOf(u"<para>");
-            if (firstPara != -1) {
-                const QString baseClass = QtDocParser::enumBaseClass(meta_enum);
-                if (baseClass != u"Enum") {
-                    const QString note = u"(inherits <teletype>enum."_s + baseClass
-                                         + u"</teletype>) "_s;
-                    doc.insert(firstPara + 6, note);
-                }
-            }
-            enumDoc.setValue(doc);
-            meta_enum.setDocumentation(enumDoc);
-        } else {
+        if (!extractEnumDocumentation(classDocumentation, meta_enum)) {
             qCWarning(lcShibokenDoc, "%s",
                       qPrintable(msgCannotFindDocumentation(sourceFileName, metaClass, meta_enum, {})));
         }
     }
 }
 
+bool QtDocParser::extractEnumDocumentation(const ClassDocumentation &classDocumentation,
+                                           AbstractMetaEnum &meta_enum)
+{
+    Documentation enumDoc;
+    const auto index = classDocumentation.indexOfEnum(meta_enum.name());
+    if (index == -1)
+        return false;
+    QString doc = classDocumentation.enums.at(index).description;
+    const auto firstPara = doc.indexOf(u"<para>");
+    if (firstPara != -1) {
+        const QString baseClass = QtDocParser::enumBaseClass(meta_enum);
+        if (baseClass != "Enum"_L1) {
+            const QString note = "(inherits <teletype>enum."_L1 + baseClass
+                                 + "</teletype>) "_L1;
+            doc.insert(firstPara + 6, note);
+        }
+    }
+    enumDoc.setValue(doc);
+    meta_enum.setDocumentation(enumDoc);
+    return true;
+}
+
 static QString qmlReferenceLink(const QFileInfo &qmlModuleFi)
 {
     QString result;
index 2ad9419718b02c293c6d1ded42cc6ced37dc7e5f..f6ba5e47af4c0da2b1b8536129fa0f5aacaf24ba 100644 (file)
@@ -13,6 +13,9 @@ class QtDocParser : public DocParser
 public:
     QtDocParser() = default;
     void fillDocumentation(const AbstractMetaClassPtr &metaClass) override;
+    void fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &f) override;
+    void fillGlobalEnumDocumentation(AbstractMetaEnum &e) override;
+
     Documentation retrieveModuleDocumentation() override;
     Documentation retrieveModuleDocumentation(const QString& name) override;
 
@@ -28,6 +31,9 @@ private:
                                               const AbstractMetaClassCPtr &metaClass,
                                               const AbstractMetaFunctionCPtr &func,
                                               QString *errorMessage);
+    static bool extractEnumDocumentation(const ClassDocumentation &classDocumentation,
+                                         AbstractMetaEnum &meta_enum);
+
 };
 
 #endif // QTDOCPARSER_H
index a1940b7620c4f97e5d157e8b36784a086847ead4..4b5da0c3ac0371fdff7508394d0439704eae440f 100644 (file)
@@ -113,10 +113,10 @@ public:
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 4);
-    const auto a = AbstractMetaClass::findClass(classes, u"A");
-    const auto b = AbstractMetaClass::findClass(classes, u"B");
-    const auto c = AbstractMetaClass::findClass(classes, u"C");
-    const auto f = AbstractMetaClass::findClass(classes, u"F");
+    const auto a = AbstractMetaClass::findClass(classes, "A");
+    const auto b = AbstractMetaClass::findClass(classes, "B");
+    const auto c = AbstractMetaClass::findClass(classes, "C");
+    const auto f = AbstractMetaClass::findClass(classes, "F");
     QVERIFY(f);
 
     QCOMPARE(a->baseClass(), nullptr);
@@ -159,11 +159,11 @@ public:
     const auto funcF = virtualFunctionsF.constFirst();
 
     QCOMPARE(funcA->ownerClass(), a);
-    QVERIFY(funcC->attributes().testFlag(AbstractMetaFunction::VirtualCppMethod));
+    QVERIFY(funcC->isVirtual());
     QCOMPARE(funcB->ownerClass(), b);
     QCOMPARE(funcC->ownerClass(), c);
-    QVERIFY(funcC->attributes().testFlag(AbstractMetaFunction::OverriddenCppMethod));
-    QVERIFY(funcF->attributes().testFlag(AbstractMetaFunction::FinalCppMethod));
+    QVERIFY(funcC->cppAttributes().testFlag(FunctionAttribute::Override));
+    QVERIFY(funcF->cppAttributes().testFlag(FunctionAttribute::Final));
 
     QCOMPARE(funcA->declaringClass(), a);
     QCOMPARE(funcB->declaringClass(), a);
@@ -196,10 +196,10 @@ class Derived : public Base {};
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto base = AbstractMetaClass::findClass(classes, u"Base");
+    const auto base = AbstractMetaClass::findClass(classes, "Base");
     QVERIFY(base);
     QVERIFY(base->isPolymorphic());
-    const auto derived = AbstractMetaClass::findClass(classes, u"Derived");
+    const auto derived = AbstractMetaClass::findClass(classes, "Derived");
     QVERIFY(derived);
     QVERIFY(derived->isPolymorphic());
 }
@@ -221,7 +221,7 @@ void TestAbstractMetaClass::testDefaultValues()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     const auto candidates = classA->queryFunctionsByName(u"method"_s);
     QCOMPARE(candidates.size(), 1);
     const auto &method = candidates.constFirst();
@@ -251,7 +251,7 @@ void TestAbstractMetaClass::testModifiedDefaultValues()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     const auto methodMatches = classA->queryFunctionsByName(u"method"_s);
     QCOMPARE(methodMatches.size(), 1);
     const auto method = methodMatches.constFirst();
@@ -277,10 +277,10 @@ void TestAbstractMetaClass::testInnerClassOfAPolymorphicOne()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QVERIFY(classA->isPolymorphic());
-    const auto classB = AbstractMetaClass::findClass(classes, u"A::B");
+    const auto classB = AbstractMetaClass::findClass(classes, "A::B");
     QVERIFY(classB);
     QVERIFY(!classB->isPolymorphic());
 }
@@ -305,11 +305,11 @@ void TestAbstractMetaClass::testForwardDeclaredInnerClass()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
-    const auto classB = AbstractMetaClass::findClass(classes, u"A::B");
+    const auto classB = AbstractMetaClass::findClass(classes, "A::B");
     QVERIFY(classB);
-    const auto fooF = classB->findFunction(u"foo");
+    const auto fooF = classB->findFunction("foo");
     QVERIFY(fooF);
 }
 
@@ -337,7 +337,7 @@ void TestAbstractMetaClass::testSpecialFunctions()
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
 
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor);
     QCOMPARE(ctors.size(), 2);
@@ -348,7 +348,7 @@ void TestAbstractMetaClass::testSpecialFunctions()
     QCOMPARE(assigmentOps.constFirst()->functionType(),
              AbstractMetaFunction::AssignmentOperatorFunction);
 
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classB);
     ctors = classB->queryFunctions(FunctionQueryOption::AnyConstructor);
     QCOMPARE(ctors.size(), 2);
@@ -403,7 +403,7 @@ void TestAbstractMetaClass::testClassDefaultConstructors()
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 6);
 
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QCOMPARE(classA->functions().size(), 2);
 
@@ -417,28 +417,28 @@ void TestAbstractMetaClass::testClassDefaultConstructors()
     QCOMPARE(ctors[1]->arguments().size(), 1);
     QCOMPARE(ctors[1]->minimalSignature(), u"A(A)");
 
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classB);
     QCOMPARE(classB->functions().size(), 2);
     QCOMPARE(classB->functions().constFirst()->minimalSignature(), u"B()");
 
-    const auto classC = AbstractMetaClass::findClass(classes, u"C");
+    const auto classC = AbstractMetaClass::findClass(classes, "C");
     QVERIFY(classC);
     QCOMPARE(classC->functions().size(), 1);
     QCOMPARE(classC->functions().constFirst()->minimalSignature(), u"C(C)");
 
-    const auto classD = AbstractMetaClass::findClass(classes, u"D");
+    const auto classD = AbstractMetaClass::findClass(classes, "D");
     QVERIFY(classD);
     QCOMPARE(classD->functions().size(), 1);
     QCOMPARE(classD->functions().constFirst()->minimalSignature(), u"D(D)");
     QVERIFY(classD->functions().constFirst()->isPrivate());
 
-    const auto classE = AbstractMetaClass::findClass(classes, u"E");
+    const auto classE = AbstractMetaClass::findClass(classes, "E");
     QVERIFY(classE);
     QVERIFY(classE->hasPrivateDestructor());
     QCOMPARE(classE->functions().size(), 0);
 
-    const auto classF = AbstractMetaClass::findClass(classes, u"F");
+    const auto classF = AbstractMetaClass::findClass(classes, "F");
     QVERIFY(classF);
 
     ctors = classF->queryFunctions(FunctionQueryOption::AnyConstructor);
@@ -471,7 +471,7 @@ void TestAbstractMetaClass::testClassInheritedDefaultConstructors()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
 
     auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor);
@@ -485,7 +485,7 @@ void TestAbstractMetaClass::testClassInheritedDefaultConstructors()
     QCOMPARE(ctors[1]->minimalSignature(), u"A(A)");
     QVERIFY(ctors[1]->isPrivate());
 
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classB);
 
     ctors = classB->queryFunctions(FunctionQueryOption::Constructors);
@@ -509,7 +509,7 @@ void TestAbstractMetaClass::testAbstractClassDefaultConstructors()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 1);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
 
     const auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors);
@@ -530,7 +530,7 @@ void TestAbstractMetaClass::testObjectTypesMustNotHaveCopyConstructors()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 1);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
 
     const auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors);
@@ -566,10 +566,10 @@ void TestAbstractMetaClass::testIsPolymorphic()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto b = AbstractMetaClass::findClass(classes, u"A");
+    const auto b = AbstractMetaClass::findClass(classes, "A");
 
     QVERIFY(!b->isPolymorphic());
-    const auto a = AbstractMetaClass::findClass(classes, u"B");
+    const auto a = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(!a->isPolymorphic());
 }
 
@@ -596,9 +596,9 @@ class Derived : public BaseAlias2 {
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto base = AbstractMetaClass::findClass(classes, u"Base");
+    const auto base = AbstractMetaClass::findClass(classes, "Base");
     QVERIFY(base);
-    const auto derived = AbstractMetaClass::findClass(classes, u"Derived");
+    const auto derived = AbstractMetaClass::findClass(classes, "Derived");
     QVERIFY(derived);
     QCOMPARE(derived->baseClasses().value(0), base);
 }
@@ -681,9 +681,9 @@ public:
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto base = AbstractMetaClass::findClass(classes, u"Base");
+    const auto base = AbstractMetaClass::findClass(classes, "Base");
     QVERIFY(base);
-    const auto derived = AbstractMetaClass::findClass(classes, u"Derived");
+    const auto derived = AbstractMetaClass::findClass(classes, "Derived");
     QVERIFY(derived);
     const auto usingMembers = derived->usingMembers();
     QCOMPARE(usingMembers.size(), 2);
@@ -735,7 +735,7 @@ void TestAbstractMetaClass::testUsingTemplateMembers()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(code.constData(), xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto valueList = AbstractMetaClass::findClass(classes, u"ValueList");
+    const auto valueList = AbstractMetaClass::findClass(classes, "ValueList");
     QVERIFY(valueList);
     auto list = valueList->templateBaseClass();
     QVERIFY(valueList->isUsingMember(list, u"append"_s, Access::Public));
@@ -765,7 +765,7 @@ public:
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto tc = AbstractMetaClass::findClass(classes, u"TestClass");
+    const auto tc = AbstractMetaClass::findClass(classes, "TestClass");
     // Verify that the constructor and 2 functions are generated.
     const auto &functions = tc->functions();
     QCOMPARE(functions.size(), 5);
index 4a2821db89869daafcd82692411e563ef14cba54..2c320c87434ee5f48dd3432cf5c1a76deafd0a1e 100644 (file)
@@ -161,7 +161,7 @@ void TestAbstractMetaType::testTypedef()
 
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 1);
-    const auto c = AbstractMetaClass::findClass(classes, u"C");
+    const auto c = AbstractMetaClass::findClass(classes, "C");
     QVERIFY(c);
     QVERIFY(c->isTypeDef());
 }
@@ -211,7 +211,7 @@ void TestAbstractMetaType::testObjectTypeUsedAsValue()
 
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 1);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     const auto overloads = classA->queryFunctionsByName(u"method"_s);
     QCOMPARE(overloads.size(), 1);
index c3d6e4a8a3101942238e8ed208bbac2f2d1e6532..a891e1e28d92d998c92e6d93f8dd4cf461b87ddf 100644 (file)
 
 using namespace Qt::StringLiterals;
 
+static constexpr auto voidT = "void"_L1;
+
 void TestAddFunction::testParsingFuncNameAndConstness()
 {
     // generic test...
-    const char sig1[] = "func(type1, const type2, const type3* const)";
+    static constexpr auto sig1 = "func(type1, const type2, const type3* const)"_L1;
     QString errorMessage;
-    auto f1 = AddedFunction::createAddedFunction(QLatin1StringView(sig1), u"void"_s,
-                                                 &errorMessage);
+    auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage);
     QVERIFY2(f1, qPrintable(errorMessage));
     QCOMPARE(f1->name(), u"func");
     QCOMPARE(f1->arguments().size(), 3);
     TypeInfo retval = f1->returnType();
-    QCOMPARE(retval.qualifiedName(), QStringList{u"void"_s});
+    QCOMPARE(retval.qualifiedName(), QStringList{voidT});
     QCOMPARE(retval.indirections(), 0);
     QCOMPARE(retval.isConstant(), false);
     QCOMPARE(retval.referenceType(), NoReference);
 
     // test with a ugly template as argument and other ugly stuff
-    const char sig2[] = "    _fu__nc_       (  type1, const type2, const Abc<int& , C<char*> *   >  * *@my_name@, const type3* const    )   const ";
-    auto f2 = AddedFunction::createAddedFunction(QLatin1StringView(sig2),
+    static constexpr auto sig2 =
+        "    _fu__nc_       (  type1, const type2, const Abc<int& , C<char*> *   >"
+        "  * *@my_name@, const type3* const    )   const "_L1;
+    auto f2 = AddedFunction::createAddedFunction(sig2,
                                                  u"const Abc<int& , C<char*> *   >  * *"_s,
                                                  &errorMessage);
     QVERIFY2(f2, qPrintable(errorMessage));
@@ -66,17 +69,14 @@ void TestAddFunction::testParsingFuncNameAndConstness()
     QVERIFY(args.at(3).name.isEmpty());
 
     // function with no args.
-    const char sig3[] = "func()";
-    auto f3 = AddedFunction::createAddedFunction(QLatin1StringView(sig3), u"void"_s,
-                                                 &errorMessage);
+    auto f3 = AddedFunction::createAddedFunction("func()"_L1, voidT, &errorMessage);
     QVERIFY2(f3, qPrintable(errorMessage));
     QCOMPARE(f3->name(), u"func");
     QCOMPARE(f3->arguments().size(), 0);
 
     // const call operator
-    const char sig4[] = "operator()(int)const";
-    auto f4 = AddedFunction::createAddedFunction(QLatin1StringView(sig4), u"int"_s,
-                                                 &errorMessage);
+    auto f4 = AddedFunction::createAddedFunction("operator()(int)const"_L1,
+                                                 "int"_L1, &errorMessage);
     QVERIFY2(f4, qPrintable(errorMessage));
     QCOMPARE(f4->name(), u"operator()");
     QCOMPARE(f4->arguments().size(), 1);
@@ -105,12 +105,12 @@ struct A {
     QVERIFY(builder);
     auto *typeDb = TypeDatabase::instance();
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     // default ctor, default copy ctor, func a() and the added functions
     QCOMPARE(classA->functions().size(), 5);
 
-    auto addedFunc = classA->findFunction(u"b");
+    auto addedFunc = classA->findFunction("b");
     QVERIFY(addedFunc);
     QCOMPARE(addedFunc->access(), Access::Protected);
     QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
@@ -131,7 +131,7 @@ struct A {
     QCOMPARE(args.at(1).defaultValueExpression(), u"4.6");
     QCOMPARE(args.at(2).type().typeEntry(), typeDb->findType(u"B"_s));
 
-    auto addedCallOperator = classA->findFunction(u"operator()");
+    auto addedCallOperator = classA->findFunction("operator()");
     QVERIFY(addedCallOperator);
 }
 
@@ -148,7 +148,7 @@ void TestAddFunction::testAddFunctionConstructor()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QCOMPARE(classA->functions().size(), 3); // default and added ctors
     const auto addedFunc = classA->functions().constLast();
@@ -171,7 +171,7 @@ void TestAddFunction::testAddFunctionTagDefaultValues()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     // default ctor, default copy ctor and the added function
     QCOMPARE(classA->functions().size(), 3);
@@ -197,7 +197,7 @@ void TestAddFunction::testAddFunctionCodeSnippets()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     const auto addedFunc = classA->functions().constLast();
     QVERIFY(addedFunc->hasInjectedCode());
@@ -205,10 +205,9 @@ void TestAddFunction::testAddFunctionCodeSnippets()
 
 void TestAddFunction::testAddFunctionWithoutParenteses()
 {
-    const char sig1[] = "func";
+    static constexpr auto sig1 = "func"_L1;
     QString errorMessage;
-    auto f1 = AddedFunction::createAddedFunction(QLatin1StringView(sig1), u"void"_s,
-                                                 &errorMessage);
+    auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage);
     QVERIFY2(f1, qPrintable(errorMessage));
     QCOMPARE(f1->name(), u"func");
     QCOMPARE(f1->arguments().size(), 0);
@@ -227,9 +226,9 @@ void TestAddFunction::testAddFunctionWithoutParenteses()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
-    const auto addedFunc = classA->findFunction(u"func");
+    const auto addedFunc = classA->findFunction(sig1);
     QVERIFY(addedFunc);
     QVERIFY(addedFunc->hasInjectedCode());
     const auto snips = addedFunc->injectedCodeSnips(TypeSystem::CodeSnipPositionAny,
@@ -239,10 +238,9 @@ void TestAddFunction::testAddFunctionWithoutParenteses()
 
 void TestAddFunction::testAddFunctionWithDefaultArgs()
 {
-    const char sig1[] = "func";
+    static constexpr auto sig1 = "func"_L1;
     QString errorMessage;
-    auto f1 = AddedFunction::createAddedFunction(QLatin1StringView(sig1), u"void"_s,
-                                                 &errorMessage);
+    auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage);
     QVERIFY2(f1, qPrintable(errorMessage));
     QCOMPARE(f1->name(), u"func");
     QCOMPARE(f1->arguments().size(), 0);
@@ -264,9 +262,9 @@ void TestAddFunction::testAddFunctionWithDefaultArgs()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
-    const auto addedFunc = classA->findFunction(u"func");
+    const auto addedFunc = classA->findFunction(sig1);
     QVERIFY(addedFunc);
     const AbstractMetaArgument &arg = addedFunc->arguments().at(1);
     QCOMPARE(arg.defaultValueExpression(), u"2");
@@ -287,7 +285,7 @@ void TestAddFunction::testAddFunctionAtModuleLevel()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
 
     auto *typeDb = TypeDatabase::instance();
@@ -306,9 +304,8 @@ void TestAddFunction::testAddFunctionAtModuleLevel()
 
 void TestAddFunction::testAddFunctionWithVarargs()
 {
-    const char sig1[] = "func(int,char,...)";
     QString errorMessage;
-    auto f1 = AddedFunction::createAddedFunction(QLatin1StringView(sig1), u"void"_s,
+    auto f1 = AddedFunction::createAddedFunction("func(int,char,...)"_L1, voidT,
                                                  &errorMessage);
     QVERIFY2(f1, qPrintable(errorMessage));
     QCOMPARE(f1->name(), u"func");
@@ -328,9 +325,9 @@ void TestAddFunction::testAddFunctionWithVarargs()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
-    const auto addedFunc = classA->findFunction(u"func");
+    const auto addedFunc = classA->findFunction("func");
     QVERIFY(addedFunc);
     const AbstractMetaArgument &arg = addedFunc->arguments().constLast();
     QVERIFY(arg.type().isVarargs());
@@ -352,9 +349,9 @@ void TestAddFunction::testAddStaticFunction()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
-    const auto addedFunc = classA->findFunction(u"func");
+    const auto addedFunc = classA->findFunction("func");
     QVERIFY(addedFunc);
     QVERIFY(addedFunc->isStatic());
 }
@@ -378,10 +375,10 @@ void TestAddFunction::testAddGlobalFunction()
     QVERIFY(builder);
     const auto globalFuncs = builder->globalFunctions();
     QCOMPARE(globalFuncs.size(), 2);
-    const auto classB = AbstractMetaClass::findClass(builder->classes(), u"B");
+    const auto classB = AbstractMetaClass::findClass(builder->classes(), "B");
     QVERIFY(classB);
-    QVERIFY(!classB->findFunction(u"globalFunc"));
-    QVERIFY(!classB->findFunction(u"globalFunc2"));
+    QVERIFY(!classB->findFunction("globalFunc"));
+    QVERIFY(!classB->findFunction("globalFunc2"));
     QVERIFY(!globalFuncs[0]->injectedCodeSnips().isEmpty());
     QVERIFY(!globalFuncs[1]->injectedCodeSnips().isEmpty());
 }
@@ -426,8 +423,8 @@ void TestAddFunction::testModifyAddedFunction()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto foo = AbstractMetaClass::findClass(classes, u"Foo");
-    const auto method = foo->findFunction(u"method");
+    const auto foo = AbstractMetaClass::findClass(classes, "Foo");
+    const auto method = foo->findFunction("method");
     QVERIFY(method);
     QCOMPARE(method->arguments().size(), 2);
     const AbstractMetaArgument &arg = method->arguments().at(1);
@@ -453,14 +450,14 @@ void TestAddFunction::testAddFunctionOnTypedef()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto foo = AbstractMetaClass::findClass(classes, u"FooInt");
+    const auto foo = AbstractMetaClass::findClass(classes, "FooInt");
     QVERIFY(foo);
     QVERIFY(foo->hasNonPrivateConstructor());
     const auto &lst = foo->queryFunctions(FunctionQueryOption::AnyConstructor);
     for (const auto &f : lst)
         QVERIFY(f->signature().startsWith(f->name()));
     QCOMPARE(lst.size(), 2);
-    const auto method = foo->findFunction(u"method");
+    const auto method = foo->findFunction("method");
     QVERIFY(method);
 }
 
index f4b22b27e7f7fcda2a8a5682bc31fff451ff3562..6e1820bedf446aac2345f1842a38c8cc50a76d27 100644 (file)
@@ -34,7 +34,7 @@ void TestArrayArgument::testArrayArgumentWithSizeDefinedByInteger()
 
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(!builder.isNull());
-    const auto classA = AbstractMetaClass::findClass(builder->classes(), u"A");
+    const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
     QVERIFY(classA);
 
     const AbstractMetaArgument &arg = classA->functions().constLast()->arguments().constFirst();
@@ -72,7 +72,7 @@ void TestArrayArgument::testArraySignature()
 
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(!builder.isNull());
-    const auto classA = AbstractMetaClass::findClass(builder->classes(), u"A");
+    const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
     QCOMPARE(functionMinimalSignature(classA, u"mi1"_s),
              u"mi1(int[5])");
     QCOMPARE(functionMinimalSignature(classA, u"mi1c"_s),
@@ -108,7 +108,7 @@ void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValue()
 
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(!builder.isNull());
-    AbstractMetaClassPtr classA = AbstractMetaClass::findClass(builder->classes(), u"A");
+    AbstractMetaClassPtr classA = AbstractMetaClass::findClass(builder->classes(), "A");
     QVERIFY(classA);
 
     auto someEnum = classA->findEnum(u"SomeEnum"_s);
@@ -139,7 +139,7 @@ void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnu
 
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
-    const auto classA = AbstractMetaClass::findClass(builder->classes(), u"A");
+    const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
     QVERIFY(classA);
 
     AbstractMetaEnum someEnum = builder->globalEnums().constFirst();
index 58aaaf9b30e2f868560cb729297783d026ad1cd7..4829e6c33498ba0ffd13d7b6fc46daaa86bbf6d9 100644 (file)
@@ -61,7 +61,7 @@ void TestCodeInjections::testReadFile()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().constData()));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QCOMPARE(classA->typeEntry()->codeSnips().size(), 1);
     QString code = classA->typeEntry()->codeSnips().constFirst().code();
     QVERIFY(code.indexOf(expected) != -1);
@@ -87,7 +87,7 @@ void TestCodeInjections::testInjectWithValidApiVersion()
                                                                 true, u"1.0"_s));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QCOMPARE(classA->typeEntry()->codeSnips().size(), 1);
 }
 
@@ -108,7 +108,7 @@ void TestCodeInjections::testInjectWithInvalidApiVersion()
     QVERIFY(builder);
 
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QCOMPARE(classA->typeEntry()->codeSnips().size(), 0);
 }
 
@@ -125,7 +125,7 @@ void TestCodeInjections::testTextStream()
     str << "\n2nd table\n|" << AlignedField("bla", 3, QTextStream::AlignLeft)
         << '|' << AlignedField(QString{}, 0, QTextStream::AlignLeft) << "|\n";
 
-static const char expected[] = R"(void foo(int a, int b) {
+constexpr auto expected = R"(void foo(int a, int b) {
     if (a == b)
         return a;
 #if Q_OS_WIN
@@ -141,9 +141,9 @@ static const char expected[] = R"(void foo(int a, int b) {
 
 2nd table
 |bla||
-)";
+)"_L1;
 
-    QCOMPARE(str.toString(), QLatin1String(expected));
+    QCOMPARE(str.toString(), expected);
 }
 
 void TestCodeInjections::testTextStreamRst()
index 5a9b7d188945694cd20524da8b364497c0fd8656..0bb72b3c11ffa1d61d6dde0d00a3a0f8ee0adfd2 100644 (file)
@@ -32,7 +32,7 @@ void TestContainer::testContainerType()
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
     //search for class A
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     auto baseContainer = classA->typeEntry()->baseContainerType();
     QVERIFY(baseContainer);
@@ -65,7 +65,7 @@ void TestContainer::testListOfValueType()
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 3);
 
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QCOMPARE(classA->templateBaseClassInstantiations().size(), 1);
     const AbstractMetaType templateInstanceType =
index 09250362214125e07e92d9330c4bea8c408ea6f0..8f2b277af308508e6c162921eb5359fd16df128b 100644 (file)
@@ -35,9 +35,9 @@ void TestConversionOperator::testConversionOperator()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
-    const auto classC = AbstractMetaClass::findClass(classes, u"C");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
+    const auto classC = AbstractMetaClass::findClass(classes, "C");
     QVERIFY(classA);
     QVERIFY(classB);
     QVERIFY(classC);
@@ -73,7 +73,7 @@ void TestConversionOperator::testConversionOperatorOfDiscardedClass()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QCOMPARE(classA->externalConversionOperators().size(), 0);
 }
@@ -97,8 +97,8 @@ void TestConversionOperator::testRemovedConversionOperator()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classA);
     QVERIFY(classB);
     QCOMPARE(classA->functions().size(), 2);
@@ -123,8 +123,8 @@ void TestConversionOperator::testConversionOperatorReturningReference()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classA);
     QVERIFY(classB);
     QCOMPARE(classA->functions().size(), 2);
@@ -157,8 +157,8 @@ void TestConversionOperator::testConversionOperatorReturningConstReference()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classA);
     QVERIFY(classB);
     QCOMPARE(classA->functions().size(), 2);
index 2d754427f43dd56a9d8b5cca3fed2f5d64028179..b5efd92a641b135413d5253deda3ae51f02fd212 100644 (file)
@@ -21,10 +21,10 @@ void TestConversionRuleTag::testConversionRuleTagWithFile()
 {
     // FIXME PYSIDE7 remove
     // temp file used later
-    const char conversionData[] = "Hi! I'm a conversion rule.";
+    constexpr auto conversionData = "Hi! I'm a conversion rule."_L1;
     QTemporaryFile file;
-    file.open();
-    QCOMPARE(file.write(conversionData), qint64(sizeof(conversionData)-1));
+    QVERIFY(file.open());
+    QCOMPARE(file.write(conversionData.constData()), conversionData.size());
     file.close();
 
     const char cppCode[] = "struct A {};\n";
@@ -37,13 +37,13 @@ void TestConversionRuleTag::testConversionRuleTagWithFile()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().data()));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     const auto typeEntry = classA->typeEntry();
     QVERIFY(typeEntry->isValue());
     auto vte = std::static_pointer_cast<const ValueTypeEntry>(typeEntry);
     QVERIFY(vte->hasTargetConversionRule());
-    QCOMPARE(vte->targetConversionRule(), QLatin1String(conversionData));
+    QCOMPARE(vte->targetConversionRule(), conversionData);
 }
 
 void TestConversionRuleTag::testConversionRuleTagReplace()
@@ -154,7 +154,7 @@ if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n\
 
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
-    const auto classA = AbstractMetaClass::findClass(builder->classes(), u"Date");
+    const auto classA = AbstractMetaClass::findClass(builder->classes(), "Date");
     QVERIFY(classA);
 
     QVERIFY(classA->typeEntry()->isValue());
index e225f91a1bce077d2839b6916697ecc19ff40aff..c3a3ebef0846eebe58a9d2ec296e3a0bd12d3499 100644 (file)
@@ -22,13 +22,13 @@ void TestCtorInformation::testCtorIsPrivate()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 3);
-    auto klass = AbstractMetaClass::findClass(classes, u"Control");
+    auto klass = AbstractMetaClass::findClass(classes, "Control");
     QVERIFY(klass);
     QVERIFY(klass->hasNonPrivateConstructor());
-    klass = AbstractMetaClass::findClass(classes, u"Subject");
+    klass = AbstractMetaClass::findClass(classes, "Subject");
     QVERIFY(klass);
     QVERIFY(!klass->hasNonPrivateConstructor());
-    klass = AbstractMetaClass::findClass(classes, u"CtorLess");
+    klass = AbstractMetaClass::findClass(classes, "CtorLess");
     QVERIFY(klass);
     QVERIFY(klass->hasNonPrivateConstructor());
 }
@@ -48,9 +48,9 @@ void TestCtorInformation::testHasNonPrivateCtor()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto base = AbstractMetaClass::findClass(classes, u"Base");
+    const auto base = AbstractMetaClass::findClass(classes, "Base");
     QCOMPARE(base->hasNonPrivateConstructor(), true);
-    const auto derived = AbstractMetaClass::findClass(classes, u"Derived");
+    const auto derived = AbstractMetaClass::findClass(classes, "Derived");
     QCOMPARE(derived->hasNonPrivateConstructor(), true);
 }
 
index 0f65b1fc8e69d8c52f613d67ab9a484bbb49c6e0..16f50e69dc3a75617b036e70c31394420cad4d9f 100644 (file)
@@ -59,13 +59,13 @@ void TestDropTypeEntries::testDropEntries()
     QVERIFY(builder);
 
     AbstractMetaClassList classes = builder->classes();
-    QVERIFY(AbstractMetaClass::findClass(classes, u"ValueA"));
-    QVERIFY(!AbstractMetaClass::findClass(classes, u"ValueB"));
-    QVERIFY(AbstractMetaClass::findClass(classes, u"ObjectA"));
-    QVERIFY(!AbstractMetaClass::findClass(classes, u"ObjectB"));
-    QVERIFY(AbstractMetaClass::findClass(classes, u"NamespaceA"));
-    QVERIFY(!AbstractMetaClass::findClass(classes, u"NamespaceA::InnerClassA"));
-    QVERIFY(!AbstractMetaClass::findClass(classes, u"NamespaceB"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "ValueA"));
+    QVERIFY(!AbstractMetaClass::findClass(classes, "ValueB"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "ObjectA"));
+    QVERIFY(!AbstractMetaClass::findClass(classes, "ObjectB"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA"));
+    QVERIFY(!AbstractMetaClass::findClass(classes, "NamespaceA::InnerClassA"));
+    QVERIFY(!AbstractMetaClass::findClass(classes, "NamespaceB"));
 
     AbstractMetaEnumList globalEnums = builder->globalEnums();
     QCOMPARE(globalEnums.size(), 1);
@@ -82,13 +82,13 @@ void TestDropTypeEntries::testDontDropEntries()
     QVERIFY(builder);
 
     AbstractMetaClassList classes = builder->classes();
-    QVERIFY(AbstractMetaClass::findClass(classes, u"ValueA"));
-    QVERIFY(AbstractMetaClass::findClass(classes, u"ValueB"));
-    QVERIFY(AbstractMetaClass::findClass(classes, u"ObjectA"));
-    QVERIFY(AbstractMetaClass::findClass(classes, u"ObjectB"));
-    QVERIFY(AbstractMetaClass::findClass(classes, u"NamespaceA"));
-    QVERIFY(AbstractMetaClass::findClass(classes, u"NamespaceA::InnerClassA"));
-    QVERIFY(AbstractMetaClass::findClass(classes, u"NamespaceB"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "ValueA"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "ValueB"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "ObjectA"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "ObjectB"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA::InnerClassA"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceB"));
 
     QCOMPARE(builder->globalEnums().size(), 2);
 
@@ -116,7 +116,7 @@ void TestDropTypeEntries::testDropEntryWithChildTags()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false,
                                                                 QString(), droppedEntries));
     QVERIFY(builder);
-    QVERIFY(!AbstractMetaClass::findClass(builder->classes(), u"ValueA"));
+    QVERIFY(!AbstractMetaClass::findClass(builder->classes(), "ValueA"));
 }
 
 
@@ -124,12 +124,12 @@ void TestDropTypeEntries::testDontDropEntryWithChildTags()
 {
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false));
     QVERIFY(builder);
-    QVERIFY(AbstractMetaClass::findClass(builder->classes(), u"ValueA"));
+    QVERIFY(AbstractMetaClass::findClass(builder->classes(), "ValueA"));
 }
 
 void TestDropTypeEntries::testConditionalParsing_data()
 {
-    const QString xml = QStringLiteral(R"(<?xml version="1.0" encoding="UTF-8"?>
+    const QString xml = R"(<?xml version="1.0" encoding="UTF-8"?>
 <root>
     <tag1>text</tag1>
     <?if keyword1?>
@@ -145,17 +145,17 @@ void TestDropTypeEntries::testConditionalParsing_data()
     <?if !keyword99?> <!-- Exclusion only -->
         <tag6>text</tag6>
     <?endif?>
-</root>)");
-
-    const QString root = QStringLiteral("root");
-    const QString tag1 = QStringLiteral("tag1");
-    const QString tag2 = QStringLiteral("tag2");
-    const QString tag3 = QStringLiteral("tag3");
-    const QString tag4 = QStringLiteral("tag4");
-    const QString tag5 = QStringLiteral("tag5");
-    const QString tag6 = QStringLiteral("tag6");
-    const QString keyword1 = QStringLiteral("keyword1");
-    const QString keyword2 = QStringLiteral("keyword2");
+</root>)"_L1;
+
+    constexpr auto root = "root"_L1;
+    constexpr auto tag1 = "tag1"_L1;
+    constexpr auto tag2 = "tag2"_L1;
+    constexpr auto tag3 = "tag3"_L1;
+    constexpr auto tag4 = "tag4"_L1;
+    constexpr auto tag5 = "tag5"_L1;
+    constexpr auto tag6 = "tag6"_L1;
+    constexpr auto keyword1 = "keyword1"_L1;
+    constexpr auto keyword2 = "keyword2"_L1;
 
     QTest::addColumn<QString>("xml");
     QTest::addColumn<QStringList>("keywords");
@@ -204,11 +204,11 @@ void TestDropTypeEntries::testConditionalParsing()
 
 void TestDropTypeEntries::testEntityParsing()
 {
-    const QString xml = QStringLiteral(R"(<?xml version="1.0" encoding="UTF-8"?>
+    const QString xml = R"(<?xml version="1.0" encoding="UTF-8"?>
 <root>
     <?entity testentity word1 word2?>
     <text>bla &testentity;</text>
-</root>)");
+</root>)"_L1;
 
     QString actual;
     ConditionalStreamReader reader(xml);
index de4cfd9f8b4683f119163b356f716b7a5879dc15..2152d39de88515dcdd08f8ed64952d419928a476 100644 (file)
@@ -28,10 +28,10 @@ private:
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    auto klass = AbstractMetaClass::findClass(classes, u"Control");
+    auto klass = AbstractMetaClass::findClass(classes, "Control");
     QVERIFY(klass);
     QVERIFY(!klass->hasPrivateDestructor());
-    klass = AbstractMetaClass::findClass(classes, u"Subject");
+    klass = AbstractMetaClass::findClass(classes, "Subject");
     QVERIFY(klass);
     QVERIFY(klass->hasPrivateDestructor());
 }
@@ -56,10 +56,10 @@ protected:
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    auto klass = AbstractMetaClass::findClass(classes, u"Control");
+    auto klass = AbstractMetaClass::findClass(classes, "Control");
     QVERIFY(klass);
     QVERIFY(!klass->hasProtectedDestructor());
-    klass = AbstractMetaClass::findClass(classes, u"Subject");
+    klass = AbstractMetaClass::findClass(classes, "Subject");
     QVERIFY(klass);
     QVERIFY(klass->hasProtectedDestructor());
 }
@@ -84,10 +84,10 @@ protected:
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    auto klass = AbstractMetaClass::findClass(classes, u"Control");
+    auto klass = AbstractMetaClass::findClass(classes, "Control");
     QVERIFY(klass);
     QVERIFY(!klass->hasVirtualDestructor());
-    klass = AbstractMetaClass::findClass(classes, u"Subject");
+    klass = AbstractMetaClass::findClass(classes, "Subject");
     QVERIFY(klass);
     QVERIFY(klass->hasVirtualDestructor());
 }
@@ -110,17 +110,17 @@ class Subject : public SubjectBase {};
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 4);
 
-    auto klass = AbstractMetaClass::findClass(classes, u"ControlBase");
+    auto klass = AbstractMetaClass::findClass(classes, "ControlBase");
     QVERIFY(klass);
     QVERIFY(!klass->hasVirtualDestructor());
-    klass = AbstractMetaClass::findClass(classes, u"Control");
+    klass = AbstractMetaClass::findClass(classes, "Control");
     QVERIFY(klass);
     QVERIFY(!klass->hasVirtualDestructor());
 
-    klass = AbstractMetaClass::findClass(classes, u"SubjectBase");
+    klass = AbstractMetaClass::findClass(classes, "SubjectBase");
     QVERIFY(klass);
     QVERIFY(klass->hasVirtualDestructor());
-    klass = AbstractMetaClass::findClass(classes, u"Subject");
+    klass = AbstractMetaClass::findClass(classes, "Subject");
     QVERIFY(klass);
     QVERIFY(klass->hasVirtualDestructor());
 }
@@ -145,10 +145,10 @@ protected:
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    auto klass = AbstractMetaClass::findClass(classes, u"Control");
+    auto klass = AbstractMetaClass::findClass(classes, "Control");
     QVERIFY(klass);
     QVERIFY(klass->isPolymorphic());
-    klass = AbstractMetaClass::findClass(classes, u"Subject");
+    klass = AbstractMetaClass::findClass(classes, "Subject");
     QVERIFY(klass);
     QVERIFY(klass->isPolymorphic());
 }
index 8a1f6c8864530936314ee7c22fbc8e52fe7a6106..c7c2b8b3bbae0fffe4ab7c834d0bd7326c9c6c3d 100644 (file)
@@ -54,7 +54,7 @@ void TestEnum::testEnumCppSignature()
              u"A::ClassEnum");
 
     // enum as parameter of a method
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QCOMPARE(classA->enums().size(), 1);
     const auto funcs = classA->queryFunctionsByName(u"method"_s);
     QVERIFY(!funcs.isEmpty());
@@ -286,7 +286,7 @@ void TestEnum::testEnumValueFromExpression()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
 
-    AbstractMetaClassPtr classA = AbstractMetaClass::findClass(builder->classes(), u"A");
+    AbstractMetaClassPtr classA = AbstractMetaClass::findClass(builder->classes(), "A");
     QVERIFY(classA);
 
     auto enumA = classA->findEnum(u"EnumA"_s);
@@ -364,7 +364,7 @@ void TestEnum::testPrivateEnum()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
 
-    const auto classA = AbstractMetaClass::findClass(builder->classes(), u"A");
+    const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
     QVERIFY(classA);
     QCOMPARE(classA->enums().size(), 2);
 
index 63d02bb7c4e86689055e246d6fec4ee18fc11c2b..fcc409a42f6afc175455dd5388eedbf960e8b60d 100644 (file)
@@ -23,7 +23,7 @@ void TestExtraInclude::testClassExtraInclude()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
 
     QList<Include> includes = classA->typeEntry()->extraIncludes();
@@ -46,7 +46,7 @@ void TestExtraInclude::testGlobalExtraIncludes()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    QVERIFY(AbstractMetaClass::findClass(classes, u"A"));
+    QVERIFY(AbstractMetaClass::findClass(classes, "A"));
 
     auto *td = TypeDatabase::instance();
     TypeSystemTypeEntryCPtr module = td->defaultTypeSystemType();
index 56b80aaef4b6e75291f7703aa0075a5f5e40abba..899d00ad49dda31de78219a6c9f69b2f5a8fb02a 100644 (file)
@@ -33,8 +33,8 @@ void TestImplicitConversions::testWithPrivateCtors()
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 3);
 
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
-    const auto classC = AbstractMetaClass::findClass(classes, u"C");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
+    const auto classC = AbstractMetaClass::findClass(classes, "C");
     const auto implicitConvs = classA->implicitConversions();
     QCOMPARE(implicitConvs.size(), 1);
     QCOMPARE(implicitConvs.constFirst()->arguments().constFirst().type().typeEntry(),
@@ -62,8 +62,8 @@ void TestImplicitConversions::testWithModifiedVisibility()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     const auto implicitConvs = classA->implicitConversions();
     QCOMPARE(implicitConvs.size(), 1);
     QCOMPARE(implicitConvs.constFirst()->arguments().constFirst().type().typeEntry(),
@@ -97,12 +97,12 @@ void TestImplicitConversions::testWithAddedCtor()
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 3);
 
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     auto implicitConvs = classA->implicitConversions();
     QCOMPARE(implicitConvs.size(), 2);
 
     // Added constructors with custom types should never result in implicit converters.
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     implicitConvs = classB->implicitConversions();
     QCOMPARE(implicitConvs.size(), 0);
 }
@@ -123,8 +123,8 @@ void TestImplicitConversions::testWithExternalConversionOperator()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     const auto implicitConvs = classA->implicitConversions();
     QCOMPARE(implicitConvs.size(), 1);
     const auto &externalConvOps = classA->externalConversionOperators();
index 63992572959cc86a20b7db137d9cb4a68b87a84b..23cf0f9ea8d9e389357e8492a1b657f1f4f3409d 100644 (file)
@@ -28,7 +28,7 @@ void TestInsertTemplate::testInsertTemplateOnClassInjectCode()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 1);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QCOMPARE(classA->typeEntry()->codeSnips().size(), 1);
     QString code = classA->typeEntry()->codeSnips().constFirst().code();
index ad9a071da494eb5733e70130580422d5869eeba6..9cf2e0cc771e1b147a503fe23271540bdb1afe6a 100644 (file)
@@ -34,7 +34,7 @@ R"(<typesystem package="Foo">
 )";
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
-    const auto classA = AbstractMetaClass::findClass(builder->classes(), u"A");
+    const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
     QVERIFY(classA);
     DocModificationList docMods = classA->typeEntry()->docModifications();
     QCOMPARE(docMods.size(), 2);
@@ -47,7 +47,7 @@ R"(<typesystem package="Foo">
     // cannot handle Qt resources.
     QTemporaryDir tempDir(QDir::tempPath() + u"/shiboken_testmodifydocXXXXXX"_s);
     QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString()));
-    const QString docFileName = u"a.xml"_s;
+    constexpr auto docFileName = "a.xml"_L1;
     QVERIFY(QFile::copy(u":/"_s + docFileName, tempDir.filePath(docFileName)));
 
     QtDocParser docParser;
@@ -95,9 +95,9 @@ void TestModifyDocumentation::testInjectAddedFunctionDocumentation()
 )XML";
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
-    const auto classA = AbstractMetaClass::findClass(builder->classes(), u"A");
+    const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
     QVERIFY(classA);
-    const auto f = classA->findFunction(u"foo");
+    const auto f = classA->findFunction("foo");
     QVERIFY(f);
     QVERIFY(f->isUserAdded());
     auto docMods = f->addedFunctionDocModifications();
index c08f5a829e2968a1c7fb5ef296e9b8c6b49f3cc0..a7d40f70a2e0b0927cb2f69526796fbb4baa020d 100644 (file)
@@ -48,8 +48,8 @@ void TestModifyFunction::testRenameArgument()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.constData(), false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
-    const auto func = classA->findFunction(u"method");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
+    const auto func = classA->findFunction("method");
     QVERIFY(func);
 
     QCOMPARE(func->argumentName(1), u"otherArg");
@@ -76,8 +76,8 @@ void TestModifyFunction::testOwnershipTransfer()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
-    const auto func = classB->findFunction(u"method");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
+    const auto func = classB->findFunction("method");
     QVERIFY(func);
 
     QCOMPARE(func->argumentTargetOwnership(func->ownerClass(), 0),
@@ -126,45 +126,45 @@ void TestModifyFunction::invalidateAfterUse()
                                                                 false, u"0.1"_s));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
-    auto func = classB->findFunction(u"call");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
+    auto func = classB->findFunction("call");
     QCOMPARE(func->modifications().size(), 1);
     QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
     QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
 
-    const auto classC = AbstractMetaClass::findClass(classes, u"C");
+    const auto classC = AbstractMetaClass::findClass(classes, "C");
     QVERIFY(classC);
-    func = classC->findFunction(u"call");
+    func = classC->findFunction("call");
     QCOMPARE(func->modifications().size(), 1);
     QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
     QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
 
-    func = classC->findFunction(u"call2");
+    func = classC->findFunction("call2");
     QCOMPARE(func->modifications().size(), 1);
     QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
     QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
 
-    AbstractMetaClassCPtr classD =  AbstractMetaClass::findClass(classes, u"D");
+    AbstractMetaClassCPtr classD =  AbstractMetaClass::findClass(classes, "D");
     QVERIFY(classD);
-    func = classD->findFunction(u"call");
+    func = classD->findFunction("call");
     QCOMPARE(func->modifications().size(), 1);
     QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
     QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
 
-    func = classD->findFunction(u"call2");
+    func = classD->findFunction("call2");
     QCOMPARE(func->modifications().size(), 1);
     QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
     QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
 
-    const auto classE = AbstractMetaClass::findClass(classes, u"E");
+    const auto classE = AbstractMetaClass::findClass(classes, "E");
     QVERIFY(classE);
-    func = classE->findFunction(u"call");
+    func = classE->findFunction("call");
     QVERIFY(func);
     QCOMPARE(func->modifications().size(), 1);
     QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
     QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
 
-    func = classE->findFunction(u"call2");
+    func = classE->findFunction("call2");
     QVERIFY(func);
     QCOMPARE(func->modifications().size(), 1);
     QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
@@ -199,13 +199,13 @@ void TestModifyFunction::testWithApiVersion()
                                                                 false, u"0.1"_s));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
-    auto func = classB->findFunction(u"method");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
+    auto func = classB->findFunction("method");
 
     auto returnOwnership = func->argumentTargetOwnership(func->ownerClass(), 0);
     QCOMPARE(returnOwnership, TypeSystem::CppOwnership);
 
-    func = classB->findFunction(u"methodB");
+    func = classB->findFunction("methodB");
     returnOwnership = func->argumentTargetOwnership(func->ownerClass(), 0);
     QVERIFY(returnOwnership != TypeSystem::CppOwnership);
 }
@@ -238,31 +238,31 @@ struct A {
                                                                 false, u"0.1"_s));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
 
     // Nothing specified, true
-    const auto f1 = classA->findFunction(u"f1");
+    const auto f1 = classA->findFunction("f1");
     QVERIFY(f1);
     QVERIFY(!f1->allowThread());
 
     // 'auto' specified, should be false for nontrivial function
-    const auto f2 = classA->findFunction(u"f2");
+    const auto f2 = classA->findFunction("f2");
     QVERIFY(f2);
     QVERIFY(f2->allowThread());
 
     // 'no' specified, should be false
-    const auto f3 = classA->findFunction(u"f3");
+    const auto f3 = classA->findFunction("f3");
     QVERIFY(f3);
     QVERIFY(!f3->allowThread());
 
     // Nothing specified, should be false for simple getter
-    const auto getter1 = classA->findFunction(u"getter1");
+    const auto getter1 = classA->findFunction("getter1");
     QVERIFY(getter1);
     QVERIFY(!getter1->allowThread());
 
     // Forced to true simple getter
-    const auto getter2 = classA->findFunction(u"getter2");
+    const auto getter2 = classA->findFunction("getter2");
     QVERIFY(getter2);
     QVERIFY(getter2->allowThread()); // Forced to true simple getter
 }
@@ -436,21 +436,21 @@ void TestModifyFunction::testScopedModifications()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode.constData(), xmlCode.constData(), false));
     QVERIFY(builder);
 
-    const auto classA = AbstractMetaClass::findClass(builder->classes(), u"A");
+    const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
     QVERIFY(classA);
 
-    auto f = classA->findFunction(QStringLiteral("unspecified"));
+    auto f = classA->findFunction("unspecified");
     QVERIFY(f);
     QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Unknown);
     QCOMPARE(f->generateExceptionHandling(), expectedGenerateUnspecified);
     QCOMPARE(f->allowThread(), expectedAllowThread);
 
-    f = classA->findFunction(QStringLiteral("nonThrowing"));
+    f = classA->findFunction("nonThrowing");
     QVERIFY(f);
     QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::NoExcept);
     QCOMPARE(f->generateExceptionHandling(), expectedGenerateNonThrowing);
 
-    f = classA->findFunction(QStringLiteral("throwing"));
+    f = classA->findFunction("throwing");
     QVERIFY(f);
     QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Throws);
     QCOMPARE(f->generateExceptionHandling(), expectedGenerateThrowing);
@@ -458,20 +458,20 @@ void TestModifyFunction::testScopedModifications()
 
 void TestModifyFunction::testSnakeCaseRenaming_data()
 {
-    QTest::addColumn<QString>("name");
-    QTest::addColumn<QString>("expected");
+    QTest::addColumn<QLatin1StringView>("name");
+    QTest::addColumn<QLatin1StringView>("expected");
     QTest::newRow("s1")
-        << QStringLiteral("snakeCaseFunc") << QStringLiteral("snake_case_func");
+        << "snakeCaseFunc"_L1 << "snake_case_func"_L1;
     QTest::newRow("s2")
-        << QStringLiteral("SnakeCaseFunc") << QStringLiteral("snake_case_func");
+        << "SnakeCaseFunc"_L1 << "snake_case_func"_L1;
     QTest::newRow("consecutive-uppercase")
-        << QStringLiteral("snakeCAseFunc") << QStringLiteral("snakeCAseFunc");
+        << "snakeCAseFunc"_L1 << "snakeCAseFunc"_L1;
 }
 
 void TestModifyFunction::testSnakeCaseRenaming()
 {
-    QFETCH(QString, name);
-    QFETCH(QString, expected);
+    QFETCH(QLatin1StringView, name);
+    QFETCH(QLatin1StringView, expected);
 
     const QString actual = AbstractMetaBuilder::getSnakeCaseName(name);
     QCOMPARE(actual, expected);
index e47aa7682783b6c5d329f2be6c37ba552eed7498..1cf4c8e0f3387c1dd62c57fe4b132713e8955463 100644 (file)
@@ -35,7 +35,7 @@ void TestMultipleInheritance::testVirtualClass()
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 4);
 
-    const auto classD = AbstractMetaClass::findClass(classes, u"D");
+    const auto classD = AbstractMetaClass::findClass(classes, "D");
     bool functionFound = false;
     for (const auto &f : classD->functions()) {
         if (f->name() == u"theBug") {
index 974dd0bd887e9743d214fb1337874fe5e17aac7f..3773e614a8184521d4b2fdb90b9308fdf3d466f7 100644 (file)
@@ -33,11 +33,11 @@ void NamespaceTest::testNamespaceMembers()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto ns = AbstractMetaClass::findClass(classes, u"Namespace");
+    const auto ns = AbstractMetaClass::findClass(classes, "Namespace");
     QVERIFY(ns);
     auto metaEnum = ns->findEnum(u"Option"_s);
     QVERIFY(metaEnum.has_value());
-    const auto func = ns->findFunction(u"foo");
+    const auto func = ns->findFunction("foo");
     QVERIFY(func);
 }
 
@@ -63,13 +63,13 @@ void NamespaceTest::testNamespaceInnerClassMembers()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto ons = AbstractMetaClass::findClass(classes, u"OuterNamespace");
+    const auto ons = AbstractMetaClass::findClass(classes, "OuterNamespace");
     QVERIFY(ons);
-    const auto ins = AbstractMetaClass::findClass(classes, u"OuterNamespace::InnerNamespace");
+    const auto ins = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace");
     QVERIFY(ins);
-    const auto sc = AbstractMetaClass::findClass(classes, u"OuterNamespace::InnerNamespace::SomeClass");
+    const auto sc = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace::SomeClass");
     QVERIFY(sc);
-    const auto meth = sc->findFunction(u"method");
+    const auto meth = sc->findFunction("method");
     QVERIFY(meth);
 }
 
index 9af411b1a07ee66b1ceeddcee1444e51e9d92c5d..10ca1a0f6a1195b8da909dc5d362015d41cbf176 100644 (file)
@@ -46,10 +46,10 @@ void TestNestedTypes::testNestedTypesModifications()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
 
-    const auto ons = AbstractMetaClass::findClass(classes, u"OuterNamespace");
+    const auto ons = AbstractMetaClass::findClass(classes, "OuterNamespace");
     QVERIFY(ons);
 
-    const auto ins = AbstractMetaClass::findClass(classes, u"OuterNamespace::InnerNamespace");
+    const auto ins = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace");
     QVERIFY(ins);
     QCOMPARE(ins->functions().size(), 1);
     QCOMPARE(ins->typeEntry()->codeSnips().size(), 1);
@@ -69,7 +69,7 @@ void TestNestedTypes::testNestedTypesModifications()
     QCOMPARE(snip.code().trimmed(), u"custom_code2();");
 
     const auto sc =
-        AbstractMetaClass::findClass(classes, u"OuterNamespace::InnerNamespace::SomeClass");
+        AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace::SomeClass");
     QVERIFY(sc);
     QCOMPARE(sc->functions().size(), 2); // default constructor and removed method
     const auto removedFunc = sc->functions().constLast();
@@ -96,11 +96,11 @@ void TestNestedTypes::testDuplicationOfNestedTypes()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 2);
-    const auto nspace = AbstractMetaClass::findClass(classes, u"Namespace");
+    const auto nspace = AbstractMetaClass::findClass(classes, "Namespace");
     QVERIFY(nspace);
-    const auto cls1 = AbstractMetaClass::findClass(classes, u"SomeClass");
+    const auto cls1 = AbstractMetaClass::findClass(classes, "SomeClass");
     QVERIFY(cls1);
-    const auto cls2 = AbstractMetaClass::findClass(classes, u"Namespace::SomeClass");
+    const auto cls2 = AbstractMetaClass::findClass(classes, "Namespace::SomeClass");
     QVERIFY(cls2);
     QCOMPARE(cls1, cls2);
     QCOMPARE(cls1->name(), u"SomeClass");
index b941094f8e6b7ac95931ea50a8a9e1184043a845..99cced09d7eeb2a6508e3b3f7ee2ff0a927dfd8a 100644 (file)
@@ -27,7 +27,7 @@ void TestPrimitiveTypeTag::testPrimitiveTypeDefaultConstructor()
 
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 1);
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classB);
 
     auto typeEntry = TypeDatabase::instance()->findPrimitiveType(u"A"_s);
index 22f8b7a8e02ef247427599d5a002c980b2cb3929..f2e26162431e8d67ef76f33760a81017286a5f82 100644 (file)
@@ -34,8 +34,8 @@ void TestRefCountTag::testReferenceCountTag()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
-    const auto func = classB->findFunction(u"keepObject");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
+    const auto func = classB->findFunction("keepObject");
     QVERIFY(func);
     const auto refCount =
         func->modifications().constFirst().argument_mods().constFirst().referenceCounts().constFirst();
@@ -68,8 +68,8 @@ void TestRefCountTag::testWithApiVersion()
                                                                 false, u"0.1"_s));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
-    const auto func = classB->findFunction(u"keepObject");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
+    const auto func = classB->findFunction("keepObject");
     QVERIFY(func);
     const auto refCount =
         func->modifications().constFirst().argument_mods().constFirst().referenceCounts().constFirst();
index e3b18758b6c3069808370ffd98e5a7604f3accd3..ae85c5a86aa95caa46504e71f58b4e35f208af2e 100644 (file)
@@ -25,9 +25,9 @@ void TestReferenceToPointer::testReferenceToPointerArgument()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classB);
-    const auto func = classB->findFunction(u"dummy");
+    const auto func = classB->findFunction("dummy");
     QVERIFY(func);
     QCOMPARE(func->arguments().constFirst().type().minimalSignature(), u"A*&");
 }
index a12675855a9008a98b1f75a5e21217bda2bfaa28..2cc82071b4f8cc2a06a29acbb3c057357ae53e19 100644 (file)
@@ -4,10 +4,15 @@
 #include "testremovefield.h"
 #include <QtTest/QTest>
 #include "testutil.h"
+#include <abstractmetaargument.h>
 #include <abstractmetafield.h>
+#include <abstractmetafunction.h>
+#include <abstractmetatype.h>
 #include <abstractmetalang.h>
 #include <typesystem.h>
 
+using namespace Qt::StringLiterals;
+
 void TestRemoveField::testRemoveField()
 {
     const char cppCode[] = "\
@@ -25,13 +30,47 @@ void TestRemoveField::testRemoveField()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QCOMPARE(classA->fields().size(), 1);
     const AbstractMetaField &fieldA = classA->fields().constFirst();
     QCOMPARE(fieldA.name(), u"fieldA");
 }
 
+// Verify that 'static constexpr' fields are seen as static/const and
+// appear fully qualified for function parameter default values.
+void TestRemoveField::testConstExprField()
+{
+    const char cppCode[] = R"(
+struct A {
+    static constexpr int constExprField = 44;
+
+    void f(int iParam=constExprField);
+};
+)";
+
+    const char xmlCode[] = R"(
+<typesystem package="Foo">
+    <value-type name='A'/>
+</typesystem>
+)";
+
+    QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+    QVERIFY(builder);
+    AbstractMetaClassList classes = builder->classes();
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
+    QVERIFY(classA);
+    const auto &fields = classA->fields();
+    QCOMPARE(fields.size(), 1);
+    QVERIFY(fields.constFirst().isStatic());
+    QVERIFY(fields.constFirst().type().isConstant());
+    const auto function = classA->findFunction("f"_L1);
+    QVERIFY(function);
+    const auto &arguments = function->arguments();
+    QCOMPARE(arguments.size(), 1);
+    QCOMPARE(arguments.constFirst().defaultValueExpression(), "A::constExprField"_L1);
+}
+
 QTEST_APPLESS_MAIN(TestRemoveField)
 
 
index febe672ceebe11c8f7f18dda74048cfd4f07d297..05912d99e37885e6dd76d14e61f25335b583aa92 100644 (file)
@@ -11,6 +11,7 @@ class TestRemoveField : public QObject
     Q_OBJECT
     private slots:
         void testRemoveField();
+        void testConstExprField();
 };
 
 #endif
index e6c5eb0c12fd2b01d23b00292ec97866b51275c7..87e318e9502a855e980655b80505b2df19b682e6 100644 (file)
@@ -33,11 +33,11 @@ void TestRemoveImplConv::testRemoveImplConv()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 3);
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classB);
-    const auto classC = AbstractMetaClass::findClass(classes, u"C");
+    const auto classC = AbstractMetaClass::findClass(classes, "C");
     QVERIFY(classC);
     const auto implConv = classC->implicitConversions();
     QCOMPARE(implConv.size(), 1);
index c2a91c8a90a9ed5ac6d8a858bc4dee542ca8802a..17a069b5ec8ca715ce0cd360b5eb9e73a393dc1c 100644 (file)
@@ -70,7 +70,7 @@ struct A {
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QCOMPARE(classA->functions().size(), 14);
     QStringList removedSignatures;
index 5e486ea511f5d348e1ead7ad609aa7f596581c0c..67ebcc606a6f2b1666a160a0fa317762767204f1 100644 (file)
@@ -49,9 +49,9 @@ void TestResolveType::testResolveReturnTypeFromParentScope()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classD = AbstractMetaClass::findClass(classes, u"A::D");
+    const auto classD = AbstractMetaClass::findClass(classes, "A::D");
     QVERIFY(classD);
-    const auto meth = classD->findFunction(u"method");
+    const auto meth = classD->findFunction("method");
     QVERIFY(meth);
     QVERIFY(meth);
 }
@@ -125,7 +125,7 @@ public:
     fixture->classType = AbstractMetaType(fixture->klass->typeEntry());
     fixture->classType.decideUsagePattern();
 
-    for (const auto &f : fixture->klass->findFunctions(u"Test"_s)) {
+    for (const auto &f : fixture->klass->findFunctions("Test")) {
         if (f->functionType() == AbstractMetaFunction::ConstructorFunction
             && f->arguments().size() == 1) {
             const auto type = f->arguments().constFirst().type();
@@ -138,7 +138,7 @@ public:
     if (fixture->intType.isVoid() || fixture->stringType.isVoid())
         return -3;
 
-    auto listFunc = fixture->klass->findFunction(u"listFunc"_s);
+    auto listFunc = fixture->klass->findFunction("listFunc");
     if (!listFunc || listFunc->arguments().size() != 1)
         return -3;
     fixture->listType = listFunc->arguments().constFirst().type();
@@ -265,7 +265,7 @@ public:
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto testClass = AbstractMetaClass::findClass(classes, u"Test");
+    const auto testClass = AbstractMetaClass::findClass(classes, "Test");
     QVERIFY(testClass);
 
     auto *tdb = TypeDatabase::instance();
index fcbdbc4e66a3f202bcd57c1df499bd6f9aca46c1..f4eecff2c56129d290b79275a799d9ffc132c6b0 100644 (file)
@@ -27,7 +27,7 @@ void TestReverseOperators::testReverseSum()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QCOMPARE(classA->functions().size(), 4);
 
@@ -69,11 +69,11 @@ void TestReverseOperators::testReverseSumWithAmbiguity()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QCOMPARE(classA->functions().size(), 4);
 
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classB);
     QCOMPARE(classB->functions().size(), 4);
 
@@ -114,7 +114,7 @@ void  TestReverseOperators::testSpaceshipOperator()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 1);
-    const auto testClass = AbstractMetaClass::findClass(classes, u"Test");
+    const auto testClass = AbstractMetaClass::findClass(classes, "Test");
     QVERIFY(testClass);
     const auto &functions = testClass->functions();
     // 6 operators should be synthesized
index eba2ecea96b210aed343a9c27347df16d19dfc30..ea37c62557e44a1ca622e92e9da24a55fbe0abb9 100644 (file)
@@ -58,9 +58,9 @@ namespace Internet {
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
 
-    const auto classB = AbstractMetaClass::findClass(classes, u"Bookmarks");
+    const auto classB = AbstractMetaClass::findClass(classes, "Bookmarks");
     QVERIFY(classB);
-    const auto func = classB->findFunction(u"list");
+    const auto func = classB->findFunction("list");
     QVERIFY(func);
     AbstractMetaType funcType = func->type();
     QVERIFY(!funcType.isVoid());
@@ -96,11 +96,11 @@ namespace Namespace {
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
 
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classB);
     QVERIFY(!classB->baseClass());
     QVERIFY(classB->baseClassName().isEmpty());
-    const auto func = classB->findFunction(u"foo");
+    const auto func = classB->findFunction("foo");
     QVERIFY(func);
     AbstractMetaType argType = func->arguments().constFirst().type();
     QCOMPARE(argType.instantiations().size(), 1);
@@ -215,12 +215,12 @@ struct List {
     QCOMPARE(templates.size(), 1);
     AbstractMetaClassCPtr list = templates.constFirst();
     // Verify that the parameter of "void append(List l)" gets fixed to "List<T>"
-    const auto append = list->findFunction(QStringLiteral("append"));
+    const auto append = list->findFunction("append");
     QVERIFY(append);
     QCOMPARE(append->arguments().size(), 1);
     QCOMPARE(append->arguments().at(0).type().cppSignature(), u"List<T>");
     // Verify that the parameter of "void erase(Iterator)" is not modified
-    const auto erase = list->findFunction(QStringLiteral("erase"));
+    const auto erase = list->findFunction("erase");
     QVERIFY(erase);
     QCOMPARE(erase->arguments().size(), 1);
     QCOMPARE(erase->arguments().at(0).type().cppSignature(), u"List::Iterator");
@@ -255,7 +255,7 @@ struct FooBars : public ListContainer<FooBar> {};
     QCOMPARE(classes.size(), 2);
     QCOMPARE(templates.size(), 1);
 
-    const auto foobars = AbstractMetaClass::findClass(classes, u"FooBars");
+    const auto foobars = AbstractMetaClass::findClass(classes, "FooBars");
     QCOMPARE(foobars->functions().size(), 4);
 
     AbstractMetaClassCPtr lc = templates.constFirst();
@@ -289,7 +289,7 @@ template<SomeEnum type> struct Future {};
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
 
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classB);
     QVERIFY(!classB->baseClass());
     QVERIFY(classB->baseClassName().isEmpty());
@@ -328,7 +328,7 @@ template<SomeEnum type> struct Future {};
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
 
-    const auto classB = AbstractMetaClass::findClass(classes, u"Namespace::B");
+    const auto classB = AbstractMetaClass::findClass(classes, "Namespace::B");
     QVERIFY(classB);
     QVERIFY(!classB->baseClass());
     QVERIFY(classB->baseClassName().isEmpty());
@@ -365,9 +365,9 @@ typedef BaseTemplateClass<TypeOne> TypeOneClass;
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 3);
 
-    const auto base = AbstractMetaClass::findClass(classes, u"BaseTemplateClass");
+    const auto base = AbstractMetaClass::findClass(classes, "BaseTemplateClass");
     QVERIFY(base);
-    const auto one = AbstractMetaClass::findClass(classes, u"TypeOneClass");
+    const auto one = AbstractMetaClass::findClass(classes, "TypeOneClass");
     QVERIFY(one);
     QCOMPARE(one->templateBaseClass(), base);
     QCOMPARE(one->functions().size(), base->functions().size());
@@ -414,7 +414,7 @@ typedef Vector<int> IntVector;
     AbstractMetaClassList classes = builder->classes();
     QCOMPARE(classes.size(), 1);
 
-    const auto vector = AbstractMetaClass::findClass(classes, u"IntVector");
+    const auto vector = AbstractMetaClass::findClass(classes, "IntVector");
     QVERIFY(vector);
     auto baseContainer = vector->typeEntry()->baseContainerType();
     QVERIFY(baseContainer);
@@ -422,11 +422,11 @@ typedef Vector<int> IntVector;
              ContainerTypeEntry::ListContainer);
     QCOMPARE(vector->functions().size(), 4);
 
-    const auto method = vector->findFunction(u"method");
+    const auto method = vector->findFunction("method");
     QVERIFY(method);
     QCOMPARE(method->signature(), u"method(const Vector<int> & vector)");
 
-    const auto otherMethod = vector->findFunction(u"otherMethod");
+    const auto otherMethod = vector->findFunction("otherMethod");
     QVERIFY(otherMethod);
     QCOMPARE(otherMethod->signature(), u"otherMethod()");
     QVERIFY(!otherMethod->type().isVoid());
@@ -540,26 +540,26 @@ void TestTemplates::testTemplateTypeDefs()
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
 
-    const auto optional = AbstractMetaClass::findClass(classes, u"Optional");
+    const auto optional = AbstractMetaClass::findClass(classes, "Optional");
     QVERIFY(optional);
 
     // Find the typedef'ed class
-    const auto optionalInt = AbstractMetaClass::findClass(classes, u"IntOptional");
+    const auto optionalInt = AbstractMetaClass::findClass(classes, "IntOptional");
     QVERIFY(optionalInt);
     QCOMPARE(optionalInt->templateBaseClass(), optional);
 
     // Find the class typedef'ed in the typesystem XML
-    const auto xmlOptionalInt = AbstractMetaClass::findClass(classes, u"XmlIntOptional");
+    const auto xmlOptionalInt = AbstractMetaClass::findClass(classes, "XmlIntOptional");
     QVERIFY(xmlOptionalInt);
     QCOMPARE(xmlOptionalInt->templateBaseClass(), optional);
 
     // Check whether the value() method now has an 'int' return
-    const auto valueMethod = optionalInt->findFunction(u"value");
+    const auto valueMethod = optionalInt->findFunction("value");
     QVERIFY(valueMethod);
     QCOMPARE(valueMethod->type().cppSignature(), u"int");
 
     // ditto for typesystem XML
-    const auto xmlValueMethod = xmlOptionalInt->findFunction(u"value");
+    const auto xmlValueMethod = xmlOptionalInt->findFunction("value");
     QVERIFY(xmlValueMethod);
     QCOMPARE(xmlValueMethod->type().cppSignature(), u"int");
 
@@ -609,7 +609,7 @@ public:
     QVERIFY(builder);
 
     AbstractMetaClassList classes = builder->classes();
-    const auto testClass = AbstractMetaClass::findClass(classes, u"Test");
+    const auto testClass = AbstractMetaClass::findClass(classes, "Test");
     QVERIFY(testClass);
 
     auto fields = testClass->fields();
@@ -618,7 +618,7 @@ public:
     QCOMPARE(fieldType.name(), u"Container1");
     QCOMPARE(fieldType.instantiations().size(), 1);
 
-    const auto derived = AbstractMetaClass::findClass(classes, u"Derived");
+    const auto derived = AbstractMetaClass::findClass(classes, "Derived");
     QVERIFY(derived);
     auto base = derived->templateBaseClass();
     QVERIFY(base);
index a7c83907b3b8bbb9c9d52fa7e2eb6c61eb2496d6..72dae8cc5f6009200c3226517d7cfbf3c602844c 100644 (file)
@@ -32,13 +32,13 @@ void TestTypeRevision::testRevisionAttr()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto rev0 = AbstractMetaClass::findClass(classes, u"Rev_0");
+    const auto rev0 = AbstractMetaClass::findClass(classes, "Rev_0");
     QCOMPARE(rev0->typeEntry()->revision(), 0);
 
-    const auto rev1 = AbstractMetaClass::findClass(classes, u"Rev_1");
+    const auto rev1 = AbstractMetaClass::findClass(classes, "Rev_1");
     QCOMPARE(rev1->typeEntry()->revision(), 1);
 
-    const auto rev2 = AbstractMetaClass::findClass(classes, u"Rev_2");
+    const auto rev2 = AbstractMetaClass::findClass(classes, "Rev_2");
     QCOMPARE(rev2->typeEntry()->revision(), 2);
 
     auto rev3 = rev2->findEnum(u"Rev_3"_s);
index 347143b7a2610c1c02ac1712513256cc0f524f90..dc4e3b2da7edb5c3c1c6878fb3729bbec7d5838e 100644 (file)
@@ -27,7 +27,7 @@ namespace TestUtil
         auto *td = TypeDatabase::instance(true);
         if (apiVersion.isEmpty())
             TypeDatabase::clearApiVersions();
-        else if (!TypeDatabase::setApiVersion(QStringLiteral("*"), apiVersion))
+        else if (!TypeDatabase::setApiVersion(QLatin1StringView("*"), apiVersion))
             return nullptr;
         td->setDropTypeEntries(dropTypeEntries);
         QBuffer buffer;
@@ -39,7 +39,7 @@ namespace TestUtil
             return nullptr;
         buffer.close();
         // parse C++ code
-        QTemporaryFile tempSource(QDir::tempPath() + QStringLiteral("/st_XXXXXX_main.cpp"));
+        QTemporaryFile tempSource(QDir::tempPath() + QLatin1StringView("/st_XXXXXX_main.cpp"));
         if (!tempSource.open()) {
             qWarning().noquote().nospace() << "Creation of temporary file failed: "
                 << tempSource.errorString();
index 19143e895bbbf2b505569efa6cb01d1984a72958..98e30eac26d69f25d7bea6490f3050cca71bb9f8 100644 (file)
@@ -26,12 +26,12 @@ void TestValueTypeDefaultCtorTag::testValueTypeDefaultCtorTagArgument()
 
     AbstractMetaClassList classes = builder->classes();
 
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
     QVERIFY(classA->typeEntry()->hasDefaultConstructor());
     QCOMPARE(classA->typeEntry()->defaultConstructor(), u"A(0, 0)");
 
-    const auto classB = AbstractMetaClass::findClass(classes, u"B");
+    const auto classB = AbstractMetaClass::findClass(classes, "B");
     QVERIFY(classB);
     QVERIFY(!classB->typeEntry()->hasDefaultConstructor());
 }
index b472cbfbad71efc7b7168b0af685b43f09d5c956..a600181a56f697defec9091f046c5796b3b2153b 100644 (file)
@@ -19,9 +19,9 @@ void TestVoidArg::testVoidParsedFunction()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
-    const auto addedFunc = classA->findFunction(u"a");
+    const auto addedFunc = classA->findFunction("a");
     QVERIFY(addedFunc);
     QCOMPARE(addedFunc->arguments().size(), 0);
 }
@@ -38,9 +38,9 @@ void TestVoidArg::testVoidAddedFunction()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
-    const auto addedFunc = classA->findFunction(u"a");
+    const auto addedFunc = classA->findFunction("a");
     QVERIFY(addedFunc);
     QCOMPARE(addedFunc->arguments().size(), 0);
 
@@ -56,9 +56,9 @@ void TestVoidArg::testVoidPointerParsedFunction()
     QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
     QVERIFY(builder);
     AbstractMetaClassList classes = builder->classes();
-    const auto classA = AbstractMetaClass::findClass(classes, u"A");
+    const auto classA = AbstractMetaClass::findClass(classes, "A");
     QVERIFY(classA);
-    const auto addedFunc = classA->findFunction(u"a");
+    const auto addedFunc = classA->findFunction("a");
     QVERIFY(addedFunc);
     QCOMPARE(addedFunc->arguments().size(), 1);
 
index d7199b9b57721982851c5fea7cc5e5677b3dccc3..228f36405a5ab016b7cee6270d73ed9259dfb5b9 100644 (file)
@@ -77,6 +77,10 @@ public:
     void putRawChar(char c) { m_str << c; }
 
     TextStream &operator<<(QStringView v) { putString(v); return *this; }
+    TextStream &operator<<(const QString &qs) { putString(QStringView{qs}); return *this; }
+    TextStream &operator<<(QLatin1StringView lv) { putString(lv.constData()); return *this; }
+    TextStream &operator<<(QUtf8StringView uv) { putString(uv.data()); return *this; }
+    TextStream &operator<<(const QByteArray &ba) { putString(ba.constData()); return *this; }
     TextStream &operator<<(QChar c) { putChar(c); return *this; }
     TextStream &operator<<(const char *s) { putString(s); return *this; }
     TextStream &operator<<(char c) { putChar(c); return *this; }
@@ -140,6 +144,12 @@ void rstCodeOff(TextStream &s);
 void rstItalic(TextStream &s);
 void rstItalicOff(TextStream &s);
 
+inline TextStream &operator<<(TextStream &str, QAnyStringView asv)
+{
+    asv.visit([&str](auto s) { str << s; });
+    return str;
+}
+
 /// Format an aligned field
 template <class T>
 class AlignedField
index 41bd0b0be1c008af34dd2b605f3d65aa232ca2ed..749c4baa33bd7a5a83a500bcc45358d50dc65104 100644 (file)
@@ -53,7 +53,7 @@ using TypeDatabaseParserContextPtr = std::shared_ptr<TypeDatabaseParserContext>;
 static QString wildcardToRegExp(QString w)
 {
     w.replace(u'?', u'.');
-    w.replace(u'*', QStringLiteral(".*"));
+    w.replace(u'*', ".*"_L1);
     return w;
 }
 
@@ -163,7 +163,8 @@ bool TypeDatabaseOptionsParser::handleBoolOption(const QString &key, OptionSourc
         break;
     case OptionSource::CommandLineSingleDash:
         if (key.startsWith(u'T')) { // "-T/path" ends up a bool option
-            m_options->m_typesystemPaths += key.sliced(1).split(QDir::listSeparator());
+            m_options->m_typesystemPaths += key.sliced(1).split(QDir::listSeparator(),
+                                                                Qt::SkipEmptyParts);
             return true;
         }
         break;
@@ -201,12 +202,14 @@ bool TypeDatabaseOptionsParser::handleOption(const QString &key, const QString &
     }
 
     if (key == u"typesystem-paths") {
-        m_options->m_typesystemPaths += value.split(QDir::listSeparator());
+        m_options->m_typesystemPaths += value.split(QDir::listSeparator(),
+                                                    Qt::SkipEmptyParts);
         return true;
     }
 
     if (key == u"force-process-system-include-paths") {
-        m_options->m_forceProcessSystemIncludes += value.split(QDir::listSeparator());
+        m_options->m_forceProcessSystemIncludes += value.split(QDir::listSeparator(),
+                                                               Qt::SkipEmptyParts);
         return true;
     }
 
@@ -285,7 +288,8 @@ TypeDatabase::TypeDatabase() : d(new TypeDatabasePrivate)
     // Environment TYPESYSTEMPATH
     if (qEnvironmentVariableIsSet(ENV_TYPESYSTEMPATH)) {
         d->m_typesystemPaths
-            += qEnvironmentVariable(ENV_TYPESYSTEMPATH).split(QDir::listSeparator());
+            += qEnvironmentVariable(ENV_TYPESYSTEMPATH).split(QDir::listSeparator(),
+                                                              Qt::SkipEmptyParts);
     }
 
     d->addBuiltInType(TypeEntryPtr(new VoidTypeEntry()));
@@ -333,12 +337,11 @@ static const IntTypeNormalizationEntries &intTypeNormalizationEntries()
     static bool firstTime = true;
     if (firstTime) {
         firstTime = false;
-        for (auto t : {"char", "short", "int", "long"}) {
-            const QString intType = QLatin1StringView(t);
+        for (const auto &intType : {"char"_L1, "short"_L1, "int"_L1, "long"_L1}) {
             if (!TypeDatabase::instance()->findType(u'u' + intType)) {
                 IntTypeNormalizationEntry entry;
-                entry.replacement = QStringLiteral("unsigned ") + intType;
-                entry.regex.setPattern(QStringLiteral("\\bu") + intType + QStringLiteral("\\b"));
+                entry.replacement = "unsigned "_L1 + intType;
+                entry.regex.setPattern("\\bu"_L1 + intType + "\\b"_L1);
                 Q_ASSERT(entry.regex.isValid());
                 result.append(entry);
             }
@@ -428,7 +431,7 @@ QStringList TypeDatabase::typesystemKeywords() const
 {
     QStringList result = d->m_typesystemKeywords;
     for (const auto &d : d->m_dropTypeEntries)
-        result.append(QStringLiteral("no_") + d);
+        result.append("no_"_L1 + d);
 
     switch (clang::emulatedCompilerLanguageLevel()) {
     case LanguageLevel::Cpp11:
@@ -914,7 +917,7 @@ bool TypeDatabase::addSuppressedWarning(const QString &warning, bool generate,
         qsizetype lastPos = 0;
         for (qsizetype a = 0, aSize = asteriskPositions.size(); a < aSize; ++a) {
             if (a)
-                pattern.append(QStringLiteral(".*"));
+                pattern.append(".*"_L1);
             const auto nextPos = asteriskPositions.at(a);
             if (nextPos > lastPos)
                 pattern.append(QRegularExpression::escape(warning.mid(lastPos, nextPos - lastPos)));
@@ -941,7 +944,7 @@ bool TypeDatabase::isSuppressedWarning(QStringView s) const
         return false;
     auto wit = std::find_if(d->m_suppressedWarnings.cbegin(), d->m_suppressedWarnings.cend(),
                             [&s] (const SuppressedWarning &e) {
-                                return e.pattern.match(s).hasMatch();
+                                return e.pattern.matchView(s).hasMatch();
                             });
     const bool found = wit != d->m_suppressedWarnings.cend();
     if (found)
@@ -1632,13 +1635,13 @@ void TypeDatabasePrivate::addBuiltInPrimitiveTypes()
     Q_ASSERT(pyUnicodeEntry && pyUnicodeEntry->isCustom());
     auto pyUnicodeCustomEntry = std::static_pointer_cast<CustomTypeEntry>(pyUnicodeEntry);
 
-    const QString stdString = u"std::string"_s;
+    constexpr auto stdString = "std::string"_L1;
     if (!m_entries.contains(stdString)) {
         addBuiltInCppStringPrimitiveType(stdString, u"std::string_view"_s,
                                          root, rootPackage,
                                          pyUnicodeCustomEntry);
     }
-    const QString stdWString = u"std::wstring"_s;
+    constexpr auto stdWString = "std::wstring"_L1;
     if (!m_entries.contains(stdWString)) {
         addBuiltInCppStringPrimitiveType(stdWString, u"std::wstring_view"_s,
                                          root, rootPackage,
index d088430114fb120caf696d003c04cdc8878c26b3..11d7bf641c5cce7a7d17b650acf9f18471f95caa 100644 (file)
@@ -147,8 +147,8 @@ Scanner::Token Scanner::nextToken(QString *errorMessage)
 
 QString Scanner::msgParseError(const QString &why) const
 {
-    return QStringLiteral("TypeParser: Unable to parse \"")
-        + QString(m_chars, m_length) + QStringLiteral("\": ") + why;
+    return "TypeParser: Unable to parse \""_L1
+        + QString(m_chars, m_length) + "\": "_L1 + why;
 }
 
 TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
@@ -199,7 +199,7 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
                 stack.top().setReferenceType(RValueReference);
                 break;
             case RValueReference:
-                const QString message = scanner.msgParseError(QStringLiteral("Too many '&' qualifiers"));
+                const QString message = scanner.msgParseError("Too many '&' qualifiers"_L1);
                 if (errorMessage)
                     *errorMessage = message;
                 else
@@ -246,7 +246,7 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
 
         case Scanner::OpenParenToken: // function pointers not supported
         case Scanner::CloseParenToken: {
-            const QString message = scanner.msgParseError(QStringLiteral("Function pointers are not supported"));
+            const QString message = scanner.msgParseError("Function pointers are not supported"_L1);
             if (errorMessage)
                 *errorMessage = message;
             else
index e5b3b63a95cf8f0b43d7c35e6068fc4cbf212baf..99d42b668c6957bc41a213f30307adf034c688fa 100644 (file)
@@ -666,6 +666,9 @@ public:
 
     CodeSnipList m_codeSnips;
     TypeSystem::SnakeCase m_snakeCase = TypeSystem::SnakeCase::Disabled;
+    QString m_subModuleOf;
+    QString m_namespaceBegin;
+    QString m_namespaceEnd;
 };
 
 TypeSystemTypeEntry::TypeSystemTypeEntry(const QString &entryName, const QVersionNumber &vr,
@@ -703,6 +706,42 @@ void TypeSystemTypeEntry::addCodeSnip(const CodeSnip &codeSnip)
     d->m_codeSnips.append(codeSnip);
 }
 
+QString TypeSystemTypeEntry::subModuleOf() const
+{
+    S_D(const TypeSystemTypeEntry);
+    return d->m_subModuleOf;
+}
+
+void TypeSystemTypeEntry::setSubModule(const QString &s)
+{
+    S_D(TypeSystemTypeEntry);
+    d->m_subModuleOf = s;
+}
+
+const QString &TypeSystemTypeEntry::namespaceBegin() const
+{
+    S_D(const TypeSystemTypeEntry);
+    return d->m_namespaceBegin;
+}
+
+void TypeSystemTypeEntry::setNamespaceBegin(const QString &p)
+{
+    S_D(TypeSystemTypeEntry);
+    d->m_namespaceBegin = p;
+}
+
+const QString &TypeSystemTypeEntry::namespaceEnd() const
+{
+    S_D(const TypeSystemTypeEntry);
+    return d->m_namespaceEnd;
+}
+
+void TypeSystemTypeEntry::setNamespaceEnd(const QString &n)
+{
+    S_D(TypeSystemTypeEntry);
+    d->m_namespaceEnd = n;
+}
+
 TypeSystem::SnakeCase TypeSystemTypeEntry::snakeCase() const
 {
     S_D(const TypeSystemTypeEntry);
@@ -1017,6 +1056,7 @@ public:
     QStringList m_rejectedEnums;
     FlagsTypeEntryPtr m_flags;
     QString m_cppType;
+    QString m_docFile;
     TypeSystem::PythonEnumType m_pythonEnumType = TypeSystem::PythonEnumType::Unspecified;
 };
 
@@ -1110,6 +1150,18 @@ QStringList EnumTypeEntry::enumValueRejections() const
     return d->m_rejectedEnums;
 }
 
+QString EnumTypeEntry::docFile() const
+{
+    S_D(const EnumTypeEntry);
+    return d->m_docFile;
+}
+
+void EnumTypeEntry::setDocFile(const QString &df)
+{
+    S_D(EnumTypeEntry);
+    d->m_docFile = df;
+}
+
 TypeEntry *EnumTypeEntry::clone() const
 {
     S_D(const EnumTypeEntry);
@@ -1741,6 +1793,7 @@ void ComplexTypeEntry::useAsTypedef(const ComplexTypeEntryCPtr &source)
     TypeEntry::useAsTypedef(source);
     d->m_qualifiedCppName = source->qualifiedCppName();
     d->m_targetType = source->targetType();
+    d->m_typeFlags.setFlag(ComplexTypeEntry::Typedef);
 }
 
 ComplexTypeEntry::ComplexTypeEntry(ComplexTypeEntryPrivate *d) :
@@ -2317,6 +2370,7 @@ public:
     }
 
     QStringList m_signatures;
+    QString m_docFile;
 };
 
 FunctionTypeEntry::FunctionTypeEntry(const QString &entryName, const QString &signature,
@@ -2344,6 +2398,18 @@ bool FunctionTypeEntry::hasSignature(const QString &signature) const
     return d->m_signatures.contains(signature);
 }
 
+QString FunctionTypeEntry::docFile() const
+{
+    S_D(const FunctionTypeEntry);
+    return d->m_docFile;
+}
+
+void FunctionTypeEntry::setDocFile(const QString &df)
+{
+    S_D(FunctionTypeEntry);
+    d->m_docFile = df;
+}
+
 TypeEntry *FunctionTypeEntry::clone() const
 {
     S_D(const FunctionTypeEntry);
index 81304e6c22412ce66e7869fefbcbf99fa2ecd162..9ecbb08a184c440e0d00720738dba1f76ee50a8d 100644 (file)
@@ -35,6 +35,7 @@ enum CodeSnipPosition {
     CodeSnipPositionBeginning,
     CodeSnipPositionEnd,
     CodeSnipPositionDeclaration,
+    CodeSnipPositionPyOverride,
     CodeSnipPositionAny
 };
 
index 59bb452a31edcca18792b37019a136a8fd98df33..5a4e12ff221138e8cae659f69e2d5cf78e75c5d8 100644 (file)
@@ -68,6 +68,7 @@ using TypedefEntryCPtr = std::shared_ptr<const TypedefEntry>;
 using TypeSystemTypeEntryCPtr = std::shared_ptr<const TypeSystemTypeEntry>;
 using ValueTypeEntryCPtr = std::shared_ptr<const ValueTypeEntry>;
 
+using ComplexTypeEntryCList = QList<ComplexTypeEntryCPtr>;
 using ContainerTypeEntryCList = QList<ContainerTypeEntryCPtr>;
 using NamespaceTypeEntryList = QList<NamespaceTypeEntryPtr>;
 using PrimitiveTypeEntryCList = QList<PrimitiveTypeEntryCPtr>;
index 3615710a9ed8b3504e1572ee1f1c0595b7e04cbf..2b686e997f12dd2af8b855ef34964fcfcb8bb12d 100644 (file)
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
 #include "typesystemparser_p.h"
+#include "anystringview_helpers.h"
 #include "addedfunction.h"
 #include "codesnip.h"
 #include "enumtypeentry.h"
 
 using namespace Qt::StringLiterals;
 
-static inline QString allowThreadAttribute() { return QStringLiteral("allow-thread"); }
-static inline QString checkFunctionAttribute() { return QStringLiteral("check-function"); }
-static inline QString copyableAttribute() { return QStringLiteral("copyable"); }
-static inline QString accessAttribute() { return QStringLiteral("access"); }
-static inline QString actionAttribute() { return QStringLiteral("action"); }
-static inline QString quoteAfterLineAttribute() { return QStringLiteral("quote-after-line"); }
-static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote-before-line"); }
-static inline QString textAttribute() { return QStringLiteral("text"); }
-static inline QString nameAttribute() { return QStringLiteral("name"); }
-static inline QString sinceAttribute() { return QStringLiteral("since"); }
-static inline QString untilAttribute() { return QStringLiteral("until"); }
-static inline QString defaultSuperclassAttribute() { return QStringLiteral("default-superclass"); }
-static inline QString deleteInMainThreadAttribute() { return QStringLiteral("delete-in-main-thread"); }
-static inline QString deprecatedAttribute() { return QStringLiteral("deprecated"); }
-static inline QString disableWrapperAttribute() { return QStringLiteral("disable-wrapper"); }
-static inline QString exceptionHandlingAttribute() { return QStringLiteral("exception-handling"); }
-static inline QString extensibleAttribute() { return QStringLiteral("extensible"); }
-static inline QString fileNameAttribute() { return QStringLiteral("file-name"); }
-static inline QString flagsAttribute() { return QStringLiteral("flags"); }
-static inline QString forceAbstractAttribute() { return QStringLiteral("force-abstract"); }
-static inline QString forceIntegerAttribute() { return QStringLiteral("force-integer"); }
-static inline QString formatAttribute() { return QStringLiteral("format"); }
-static inline QString generateUsingAttribute() { return QStringLiteral("generate-using"); }
-static inline QString generateFunctionsAttribute() { return QStringLiteral("generate-functions"); }
-static inline QString classAttribute() { return QStringLiteral("class"); }
-static inline QString generateAttribute() { return QStringLiteral("generate"); }
-static inline QString generateGetSetDefAttribute() { return QStringLiteral("generate-getsetdef"); }
-static inline QString genericClassAttribute() { return QStringLiteral("generic-class"); }
-static inline QString indexAttribute() { return QStringLiteral("index"); }
-static inline QString invalidateAfterUseAttribute() { return QStringLiteral("invalidate-after-use"); }
-static inline QString isNullAttribute() { return QStringLiteral("isNull"); }
-static inline QString locationAttribute() { return QStringLiteral("location"); }
-static inline QString modifiedTypeAttribute() { return QStringLiteral("modified-type"); }
-static inline QString opaqueContainerAttribute() { return QStringLiteral("opaque-containers"); }
-static inline QString operatorBoolAttribute() { return QStringLiteral("operator-bool"); }
-static inline QString parentManagementAttribute() { return QStringLiteral("parent-management"); }
-static inline QString pyiTypeAttribute() { return QStringLiteral("pyi-type"); }
-static inline QString overloadNumberAttribute() { return QStringLiteral("overload-number"); }
-static inline QString ownershipAttribute() { return QStringLiteral("owner"); }
-static inline QString packageAttribute() { return QStringLiteral("package"); }
-static inline QString positionAttribute() { return QStringLiteral("position"); }
-static inline QString preferredConversionAttribute() { return QStringLiteral("preferred-conversion"); }
-static inline QString preferredTargetLangTypeAttribute() { return QStringLiteral("preferred-target-lang-type"); }
-static inline QString pythonEnumTypeAttribute() { return QStringLiteral("python-type"); }
-static inline QString cppEnumTypeAttribute() { return QStringLiteral("cpp-type"); }
-static inline QString qtMetaTypeAttribute() { return QStringLiteral("qt-register-metatype"); }
-static inline QString removeAttribute() { return QStringLiteral("remove"); }
-static inline QString renameAttribute() { return QStringLiteral("rename"); }
-static inline QString readAttribute() { return QStringLiteral("read"); }
-static inline QString targetLangNameAttribute() { return QStringLiteral("target-lang-name"); }
-static inline QString writeAttribute() { return QStringLiteral("write"); }
-static inline QString opaqueContainerFieldAttribute() { return QStringLiteral("opaque-container"); }
-static inline QString replaceAttribute() { return QStringLiteral("replace"); }
-static inline QString toAttribute() { return QStringLiteral("to"); }
-static inline QString signatureAttribute() { return QStringLiteral("signature"); }
-static inline QString snippetAttribute() { return QStringLiteral("snippet"); }
-static inline QString snakeCaseAttribute() { return QStringLiteral("snake-case"); }
-static inline QString staticAttribute() { return QStringLiteral("static"); }
-static inline QString classmethodAttribute() { return QStringLiteral("classmethod"); }
-static inline QString threadAttribute() { return QStringLiteral("thread"); }
-static inline QString sourceAttribute() { return QStringLiteral("source"); }
-static inline QString streamAttribute() { return QStringLiteral("stream"); }
-static inline QString privateAttribute() { return QStringLiteral("private"); }
-static inline QString xPathAttribute() { return QStringLiteral("xpath"); }
-static inline QString virtualSlotAttribute() { return QStringLiteral("virtual-slot"); }
-static inline QString visibleAttribute() { return QStringLiteral("visible"); }
-static inline QString enumIdentifiedByValueAttribute() { return QStringLiteral("identified-by-value"); }
-
-static inline QString noAttributeValue() { return QStringLiteral("no"); }
-static inline QString yesAttributeValue() { return QStringLiteral("yes"); }
-static inline QString trueAttributeValue() { return QStringLiteral("true"); }
-static inline QString falseAttributeValue() { return QStringLiteral("false"); }
+constexpr auto allowThreadAttribute = "allow-thread"_L1;
+constexpr auto checkFunctionAttribute = "check-function"_L1;
+constexpr auto copyableAttribute = "copyable"_L1;
+constexpr auto accessAttribute = "access"_L1;
+constexpr auto actionAttribute = "action"_L1;
+constexpr auto quoteAfterLineAttribute = "quote-after-line"_L1;
+constexpr auto quoteBeforeLineAttribute = "quote-before-line"_L1;
+constexpr auto textAttribute = "text"_L1;
+constexpr auto nameAttribute = "name"_L1;
+constexpr auto sinceAttribute = "since"_L1;
+constexpr auto untilAttribute = "until"_L1;
+constexpr auto defaultSuperclassAttribute = "default-superclass"_L1;
+constexpr auto deleteInMainThreadAttribute = "delete-in-main-thread"_L1;
+constexpr auto deprecatedAttribute = "deprecated"_L1;
+constexpr auto disableWrapperAttribute = "disable-wrapper"_L1;
+constexpr auto docFileAttribute = "doc-file"_L1;
+constexpr auto exceptionHandlingAttribute = "exception-handling"_L1;
+constexpr auto extensibleAttribute = "extensible"_L1;
+constexpr auto fileNameAttribute = "file-name"_L1;
+constexpr auto fileAttribute = "file"_L1;
+constexpr auto flagsAttribute = "flags"_L1;
+constexpr auto forceAbstractAttribute = "force-abstract"_L1;
+constexpr auto forceIntegerAttribute = "force-integer"_L1;
+constexpr auto formatAttribute = "format"_L1;
+constexpr auto generateUsingAttribute = "generate-using"_L1;
+constexpr auto generateFunctionsAttribute = "generate-functions"_L1;
+constexpr auto classAttribute = "class"_L1;
+constexpr auto generateAttribute = "generate"_L1;
+constexpr auto generateGetSetDefAttribute = "generate-getsetdef"_L1;
+constexpr auto genericClassAttribute = "generic-class"_L1;
+constexpr auto indexAttribute = "index"_L1;
+constexpr auto invalidateAfterUseAttribute = "invalidate-after-use"_L1;
+constexpr auto isNullAttribute = "isNull"_L1;
+constexpr auto locationAttribute = "location"_L1;
+constexpr auto modifiedTypeAttribute = "modified-type"_L1;
+constexpr auto opaqueContainerAttribute = "opaque-containers"_L1;
+constexpr auto operatorBoolAttribute = "operator-bool"_L1;
+constexpr auto parentManagementAttribute = "parent-management"_L1;
+constexpr auto pyiTypeAttribute = "pyi-type"_L1;
+constexpr auto overloadNumberAttribute = "overload-number"_L1;
+constexpr auto ownershipAttribute = "owner"_L1;
+constexpr auto packageAttribute = "package"_L1;
+constexpr auto polymorphicBaseAttribute = "polymorphic-base"_L1;
+constexpr auto positionAttribute = "position"_L1;
+constexpr auto preferredConversionAttribute = "preferred-conversion"_L1;
+constexpr auto preferredTargetLangTypeAttribute = "preferred-target-lang-type"_L1;
+constexpr auto pythonEnumTypeAttribute = "python-type"_L1;
+constexpr auto pythonOverrideAttribute = "python-override"_L1;
+constexpr auto cppEnumTypeAttribute = "cpp-type"_L1;
+constexpr auto qtMetaObjectFunctionsAttribute = "qt-metaobject"_L1;
+constexpr auto qtMetaTypeAttribute = "qt-register-metatype"_L1;
+constexpr auto removeAttribute = "remove"_L1;
+constexpr auto renameAttribute = "rename"_L1;
+constexpr auto readAttribute = "read"_L1;
+constexpr auto targetLangNameAttribute = "target-lang-name"_L1;
+constexpr auto writeAttribute = "write"_L1;
+constexpr auto opaqueContainerFieldAttribute = "opaque-container"_L1;
+constexpr auto replaceAttribute = "replace"_L1;
+constexpr auto toAttribute = "to"_L1;
+constexpr auto signatureAttribute = "signature"_L1;
+constexpr auto snippetAttribute = "snippet"_L1;
+constexpr auto snakeCaseAttribute = "snake-case"_L1;
+constexpr auto staticAttribute = "static"_L1;
+constexpr auto classmethodAttribute = "classmethod"_L1;
+constexpr auto threadAttribute = "thread"_L1;
+constexpr auto sourceAttribute = "source"_L1;
+constexpr auto streamAttribute = "stream"_L1;
+constexpr auto privateAttribute = "private"_L1;
+constexpr auto xPathAttribute = "xpath"_L1;
+constexpr auto virtualSlotAttribute = "virtual-slot"_L1;
+constexpr auto visibleAttribute = "visible"_L1;
+constexpr auto enumIdentifiedByValueAttribute = "identified-by-value"_L1;
+constexpr auto subModuleOfAttribute = "submodule-of"_L1;
+
+constexpr auto noAttributeValue = "no"_L1;
+constexpr auto yesAttributeValue = "yes"_L1;
+constexpr auto trueAttributeValue = "true"_L1;
+constexpr auto falseAttributeValue = "false"_L1;
 
 static bool isTypeEntry(StackElement el)
 {
@@ -146,7 +153,7 @@ static bool setRejectionRegularExpression(const QString &patternIn,
     if (patternIn.startsWith(u'^') && patternIn.endsWith(u'$'))
         pattern = patternIn;
     else if (patternIn == u"*")
-        pattern = QStringLiteral("^.*$");
+        pattern = "^.*$"_L1;
     else
         pattern = u'^' + QRegularExpression::escape(patternIn) + u'$';
     re->setPattern(pattern);
@@ -157,15 +164,20 @@ static bool setRejectionRegularExpression(const QString &patternIn,
     return true;
 }
 
+static inline bool hasFileSnippetAttributes(const QXmlStreamAttributes *attributes)
+{
+    return attributes->hasAttribute(fileAttribute);
+}
+
 // Extract a snippet from a file within annotation "// @snippet label".
 std::optional<QString>
     extractSnippet(const QString &code, const QString &snippetLabel)
 {
     if (snippetLabel.isEmpty())
         return code;
-    const QString pattern = QStringLiteral(R"(^\s*//\s*@snippet\s+)")
+    const QString pattern = R"(^\s*//\s*@snippet\s+)"_L1
         + QRegularExpression::escape(snippetLabel)
-        + QStringLiteral(R"(\s*$)");
+        + R"(\s*$)"_L1;
     const QRegularExpression snippetRe(pattern);
     Q_ASSERT(snippetRe.isValid());
 
@@ -187,48 +199,31 @@ std::optional<QString>
     return CodeSnipAbstract::fixSpaces(result);
 }
 
-template <class EnumType, Qt::CaseSensitivity cs = Qt::CaseInsensitive>
+template <class EnumType>
 struct EnumLookup
 {
     QStringView name;
     EnumType value;
 };
 
-template <class EnumType, Qt::CaseSensitivity cs>
-bool operator==(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2)
-{
-    return e1.name.compare(e2.name, cs) == 0;
-}
-
-template <class EnumType, Qt::CaseSensitivity cs>
-bool operator<(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2)
-{
-    return e1.name.compare(e2.name, cs) < 0;
-}
-
 // Helper macros to define lookup functions that take a QStringView needle
 // and an optional default return value.
 #define ENUM_LOOKUP_BEGIN(EnumType, caseSensitivity, functionName) \
 static std::optional<EnumType> functionName(QStringView needle) \
 { \
-    using HaystackEntry = EnumLookup<EnumType, caseSensitivity>; \
-    static const HaystackEntry haystack[] =
-
-#define ENUM_LOOKUP_LINEAR_SEARCH() \
-    const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \
-    const auto it = std::find(haystack, end, HaystackEntry{needle, {} }); \
+    using HaystackEntry = EnumLookup<EnumType>; \
+    constexpr auto cs = caseSensitivity; \
+    static constexpr HaystackEntry haystack[] =
+
+#define ENUM_LOOKUP_LINEAR_SEARCH \
+    auto pred = [cs, needle](const HaystackEntry &he) { \
+        return he.name.compare(needle, cs) == 0; \
+    }; \
+    auto end = std::cend(haystack); \
+    auto it = std::find_if(std::cbegin(haystack), end, pred); \
     if (it != end) \
         return it->value; \
-    return {}; \
-}
-
-#define ENUM_LOOKUP_BINARY_SEARCH() \
-    const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \
-    const HaystackEntry needleEntry{needle, {} }; \
-    const auto lb = std::lower_bound(haystack, end, needleEntry); \
-    if (lb != end && *lb == needleEntry) \
-        return lb->value; \
-    return {}; \
+    return std::nullopt; \
 }
 
 ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive,
@@ -240,7 +235,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive,
         {u"no", TypeSystem::AllowThread::Disallow},
         {u"false", TypeSystem::AllowThread::Disallow},
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 
 ENUM_LOOKUP_BEGIN(TypeSystem::BoolCast, Qt::CaseInsensitive,
@@ -251,7 +246,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::BoolCast, Qt::CaseInsensitive,
         {u"no", TypeSystem::BoolCast::Disabled},
         {u"false", TypeSystem::BoolCast::Disabled},
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(TypeSystem::PythonEnumType, Qt::CaseSensitive,
                   pythonEnumTypeFromAttribute)
@@ -261,7 +256,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::PythonEnumType, Qt::CaseSensitive,
         {u"Flag", TypeSystem::PythonEnumType::Flag},
         {u"IntFlag", TypeSystem::PythonEnumType::IntFlag},
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(TypeSystem::QtMetaTypeRegistration, Qt::CaseSensitive,
                   qtMetaTypeFromAttribute)
@@ -272,7 +267,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::QtMetaTypeRegistration, Qt::CaseSensitive,
         {u"no", TypeSystem::QtMetaTypeRegistration::Disabled},
         {u"false", TypeSystem::QtMetaTypeRegistration::Disabled},
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive,
                   languageFromAttribute)
@@ -282,7 +277,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive,
         {u"shell", TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe
         {u"target", TypeSystem::TargetLangCode}  // em algum lugar do cpp
     };
-ENUM_LOOKUP_BINARY_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive,
                    ownershipFromFromAttribute)
@@ -291,7 +286,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive,
         {u"c++", TypeSystem::CppOwnership},
         {u"default", TypeSystem::DefaultOwnership}
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive,
                   addedFunctionAccessFromAttribute)
@@ -299,7 +294,7 @@ ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive,
         {u"public", AddedFunction::Public},
         {u"protected", AddedFunction::Protected},
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(FunctionModification::ModifierFlag, Qt::CaseSensitive,
                   modifierFromAttribute)
@@ -307,12 +302,11 @@ ENUM_LOOKUP_BEGIN(FunctionModification::ModifierFlag, Qt::CaseSensitive,
         {u"private", FunctionModification::Private},
         {u"public", FunctionModification::Public},
         {u"protected", FunctionModification::Protected},
-        {u"friendly", FunctionModification::Friendly},
         {u"rename", FunctionModification::Rename},
         {u"final", FunctionModification::Final},
         {u"non-final", FunctionModification::NonFinal}
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive,
                   referenceCountFromAttribute)
@@ -323,7 +317,7 @@ ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive,
         {u"set", ReferenceCount::Set},
         {u"ignore", ReferenceCount::Ignore}
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive,
                   argumentOwnerActionFromAttribute)
@@ -331,16 +325,17 @@ ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive,
         {u"add", ArgumentOwner::Add},
         {u"remove", ArgumentOwner::Remove}
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(TypeSystem::CodeSnipPosition, Qt::CaseInsensitive,
                   codeSnipPositionFromAttribute)
     {
         {u"beginning", TypeSystem::CodeSnipPositionBeginning},
         {u"end", TypeSystem::CodeSnipPositionEnd},
-        {u"declaration", TypeSystem::CodeSnipPositionDeclaration}
+        {u"declaration", TypeSystem::CodeSnipPositionDeclaration},
+        {u"override", TypeSystem::CodeSnipPositionPyOverride}
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive,
                   locationFromAttribute)
@@ -349,7 +344,7 @@ ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive,
         {u"local", Include::LocalPath},
         {u"target", Include::TargetLangImport}
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive,
                   docModificationFromAttribute)
@@ -358,7 +353,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive,
         {u"prepend", TypeSystem::DocModificationPrepend},
         {u"replace", TypeSystem::DocModificationReplace}
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(ContainerTypeEntry::ContainerKind, Qt::CaseSensitive,
                   containerTypeFromAttribute)
@@ -377,7 +372,7 @@ ENUM_LOOKUP_BEGIN(ContainerTypeEntry::ContainerKind, Qt::CaseSensitive,
         {u"pair", ContainerTypeEntry::PairContainer},
         {u"span", ContainerTypeEntry::SpanContainer}
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive,
                   typeRejectionFromAttribute)
@@ -389,7 +384,7 @@ ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive,
         {u"argument-type", TypeRejection::ArgumentType},
         {u"return-type", TypeRejection::ReturnType}
     };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive,
                   exceptionHandlingFromAttribute)
@@ -401,7 +396,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive,
     {u"yes", TypeSystem::ExceptionHandling::On},
     {u"true", TypeSystem::ExceptionHandling::On},
 };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(TypeSystem::SmartPointerType, Qt::CaseSensitive,
                   smartPointerTypeFromAttribute)
@@ -411,7 +406,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::SmartPointerType, Qt::CaseSensitive,
     {u"value-handle", TypeSystem::SmartPointerType::ValueHandle},
     {u"shared", TypeSystem::SmartPointerType::Shared}
 };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 template <class EnumType>
 static std::optional<EnumType>
@@ -522,7 +517,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::SnakeCase, Qt::CaseSensitive,
     {u"true", TypeSystem::SnakeCase::Enabled},
     {u"both", TypeSystem::SnakeCase::Both},
 };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 ENUM_LOOKUP_BEGIN(TypeSystem::Visibility, Qt::CaseSensitive,
                   visibilityFromAttribute)
@@ -533,10 +528,10 @@ ENUM_LOOKUP_BEGIN(TypeSystem::Visibility, Qt::CaseSensitive,
     {u"yes", TypeSystem::Visibility::Visible},
     {u"true", TypeSystem::Visibility::Visible},
 };
-ENUM_LOOKUP_LINEAR_SEARCH()
+ENUM_LOOKUP_LINEAR_SEARCH
 
 static int indexOfAttribute(const QXmlStreamAttributes &atts,
-                            QStringView name)
+                            QAnyStringView name)
 {
     for (qsizetype i = 0, size = atts.size(); i < size; ++i) {
         if (atts.at(i).qualifiedName() == name)
@@ -692,7 +687,7 @@ static QString msgReaderError(const ConditionalStreamReader &reader, const QStri
 }
 
 static QString msgUnimplementedElementWarning(const ConditionalStreamReader &reader,
-                                              QStringView name)
+                                              QAnyStringView name)
 {
     QString message;
     QTextStream(&message) << "The element \"" << name
@@ -717,7 +712,7 @@ static inline QString msgUnimplementedAttributeWarning(const ConditionalStreamRe
 
 static QString
     msgUnimplementedAttributeValueWarning(const ConditionalStreamReader &reader,
-                                          QStringView name, QStringView value)
+                                          QAnyStringView name, QAnyStringView value)
 {
     QString message;
     QTextStream(&message) << "The value \"" << value
@@ -737,9 +732,9 @@ static inline
 static bool addRejection(TypeDatabase *database, bool generate, QXmlStreamAttributes *attributes,
                          QString *errorMessage)
 {
-    const auto classIndex = indexOfAttribute(*attributes, classAttribute());
+    const auto classIndex = indexOfAttribute(*attributes, classAttribute);
     if (classIndex == -1) {
-        *errorMessage = msgMissingAttribute(classAttribute());
+        *errorMessage = msgMissingAttribute(classAttribute);
         return false;
     }
 
@@ -1125,7 +1120,7 @@ bool TypeSystemParser::characters(const String &ch)
 
 bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts)
 {
-    const QString fileName = atts.value(nameAttribute()).toString();
+    const QString fileName = atts.value(nameAttribute).toString();
     if (fileName.isEmpty()) {
         m_error = u"Required attribute 'name' missing for include-file tag."_s;
         return false;
@@ -1140,11 +1135,11 @@ bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts)
         }
     }
 
-    const auto quoteFrom = atts.value(quoteAfterLineAttribute());
+    const auto quoteFrom = atts.value(quoteAfterLineAttribute);
     bool foundFromOk = quoteFrom.isEmpty();
     bool from = quoteFrom.isEmpty();
 
-    const auto quoteTo = atts.value(quoteBeforeLineAttribute());
+    const auto quoteTo = atts.value(quoteBeforeLineAttribute);
     bool foundToOk = quoteTo.isEmpty();
     bool to = true;
 
@@ -1164,10 +1159,10 @@ bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts)
         }
     }
     if (!foundFromOk || !foundToOk) {
-        QString fromError = QStringLiteral("Could not find quote-after-line='%1' in file '%2'.")
-                                           .arg(quoteFrom.toString(), fileName);
-        QString toError = QStringLiteral("Could not find quote-before-line='%1' in file '%2'.")
-                                         .arg(quoteTo.toString(), fileName);
+        QString fromError = QString::fromLatin1("Could not find quote-after-line='%1' in file '%2'.")
+                                                .arg(quoteFrom.toString(), fileName);
+        QString toError = QString::fromLatin1("Could not find quote-before-line='%1' in file '%2'.")
+                                              .arg(quoteTo.toString(), fileName);
 
         if (!foundToOk)
             m_error = toError;
@@ -1181,29 +1176,27 @@ bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts)
     return true;
 }
 
-static bool convertBoolean(QStringView value, const QString &attributeName, bool defaultValue)
+static bool convertBoolean(QStringView value, QAnyStringView attributeName, bool defaultValue)
 {
-    if (value.compare(trueAttributeValue(), Qt::CaseInsensitive) == 0
-        || value.compare(yesAttributeValue(), Qt::CaseInsensitive) == 0) {
+    if (value.compare(trueAttributeValue, Qt::CaseInsensitive) == 0
+        || value.compare(yesAttributeValue, Qt::CaseInsensitive) == 0) {
         return true;
     }
-    if (value.compare(falseAttributeValue(), Qt::CaseInsensitive) == 0
-        || value.compare(noAttributeValue(), Qt::CaseInsensitive) == 0) {
+    if (value.compare(falseAttributeValue, Qt::CaseInsensitive) == 0
+        || value.compare(noAttributeValue, Qt::CaseInsensitive) == 0) {
         return false;
     }
-    const QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
-                                      .arg(value)
-                                      .arg(attributeName,
-                                           defaultValue ? yesAttributeValue() : noAttributeValue());
-
-    qCWarning(lcShiboken).noquote().nospace() << warn;
+    qCWarning(lcShiboken).noquote().nospace() << "Boolean value '" << value
+        << "' not supported in attribute '" << attributeName
+        << "'. Use 'yes' or 'no'. Defaulting to '"
+        << (defaultValue ? yesAttributeValue : noAttributeValue) << "'.";
     return defaultValue;
 }
 
 static bool convertRemovalAttribute(QStringView value)
 {
     return value == u"all" // Legacy
-        || convertBoolean(value, removeAttribute(), false);
+        || convertBoolean(value, removeAttribute, false);
 }
 
 // Check whether an entry should be dropped, allowing for dropping the module
@@ -1229,7 +1222,7 @@ static bool shouldDropTypeEntry(const TypeDatabase *db,
 static QString checkSignatureError(const QString& signature, const QString& tag)
 {
     QString funcName = signature.left(signature.indexOf(u'(')).trimmed();
-    static const QRegularExpression whiteSpace(QStringLiteral("\\s"));
+    static const QRegularExpression whiteSpace("\\s"_L1);
     Q_ASSERT(whiteSpace.isValid());
     if (!funcName.startsWith(u"operator ") && funcName.contains(whiteSpace)) {
         return QString::fromLatin1("Error in <%1> tag signature attribute '%2'.\n"
@@ -1308,7 +1301,7 @@ CustomTypeEntryPtr TypeSystemParser::parseCustomTypeEntry(const ConditionalStrea
     auto result = std::make_shared<CustomTypeEntry>(name, since, m_contextStack.top()->entry);
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == checkFunctionAttribute())
+        if (name == checkFunctionAttribute)
             result->setCheckFunction(attributes->takeAt(i).value().toString());
     }
     return result;
@@ -1344,9 +1337,9 @@ FlagsTypeEntryPtr
     const QString targetLangFlagName = lst.join(u'.');
     const QString &targetLangQualifier = enumEntry->targetLangQualifier();
     if (targetLangFlagName != targetLangQualifier) {
-        qCWarning(lcShiboken).noquote().nospace()
-            << QStringLiteral("enum %1 and flags %2 (%3) differ in qualifiers")
-                              .arg(targetLangQualifier, lst.value(0), targetLangFlagName);
+        qCWarning(lcShiboken, "enum %s and flags %s (%s) differ in qualifiers",
+                  qPrintable(targetLangQualifier), qPrintable(lst.value(0)),
+                  qPrintable(targetLangFlagName));
     }
 
     ftype->setFlagsName(name);
@@ -1452,16 +1445,16 @@ PrimitiveTypeEntryPtr
         return nullptr;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == targetLangNameAttribute()) {
+        if (name == targetLangNameAttribute) {
             type->setTargetLangName(attributes->takeAt(i).value().toString());
         } else if (name == u"target-lang-api-name") {
             targetLangApiName = attributes->takeAt(i).value().toString();
-        } else if (name == preferredConversionAttribute()) {
+        } else if (name == preferredConversionAttribute) {
             qCWarning(lcShiboken, "%s",
                       qPrintable(msgUnimplementedAttributeWarning(reader, name)));
-        } else if (name == preferredTargetLangTypeAttribute()) {
+        } else if (name == preferredTargetLangTypeAttribute) {
             const bool v = convertBoolean(attributes->takeAt(i).value(),
-                                          preferredTargetLangTypeAttribute(), true);
+                                          preferredTargetLangTypeAttribute, true);
             type->setPreferredTargetLangType(v);
         } else if (name == u"default-constructor") {
              type->setDefaultConstructor(attributes->takeAt(i).value().toString());
@@ -1535,7 +1528,7 @@ ContainerTypeEntryPtr
 
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == opaqueContainerAttribute()) {
+        if (name == opaqueContainerAttribute) {
             const auto attribute = attributes->takeAt(i);
             OpaqueContainers oc;
             if (!parseOpaqueContainers(attribute.value(), &oc))
@@ -1553,16 +1546,16 @@ bool TypeSystemParser::parseOpaqueContainerElement(QXmlStreamAttributes *attribu
     OpaqueContainers oc;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == nameAttribute()) {
+        if (name == nameAttribute) {
             containerName = attributes->takeAt(i).value().toString();
-        } else if (name == opaqueContainerAttribute()) {
+        } else if (name == opaqueContainerAttribute) {
             const auto attribute = attributes->takeAt(i);
             if (!parseOpaqueContainers(attribute.value(), &oc))
                 return false;
         }
     }
     if (containerName.isEmpty()) {
-        m_error = msgMissingAttribute(nameAttribute());
+        m_error = msgMissingAttribute(nameAttribute);
         return false;
     }
     m_context->opaqueContainerHash[containerName].append(oc);
@@ -1589,10 +1582,12 @@ EnumTypeEntryPtr
         } else if (name == u"lower-bound") {
             qCWarning(lcShiboken, "%s",
                       qPrintable(msgUnimplementedAttributeWarning(reader, name)));
-        } else if (name == forceIntegerAttribute()) {
+        } else if (name == docFileAttribute) {
+            entry->setDocFile(attributes->takeAt(i).value().toString());
+        } else if (name == forceIntegerAttribute) {
             qCWarning(lcShiboken, "%s",
                       qPrintable(msgUnimplementedAttributeWarning(reader, name)));
-        } else if (name == pythonEnumTypeAttribute()) {
+        } else if (name == pythonEnumTypeAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto typeOpt = pythonEnumTypeFromAttribute(attribute.value());
             if (typeOpt.has_value()) {
@@ -1601,12 +1596,12 @@ EnumTypeEntryPtr
                 qCWarning(lcShiboken, "%s",
                           qPrintable(msgInvalidAttributeValue(attribute)));
             }
-        } else if (name == cppEnumTypeAttribute()) {
+        } else if (name == cppEnumTypeAttribute) {
             entry->setCppType(attributes->takeAt(i).value().toString());
-        } else if (name == extensibleAttribute()) {
+        } else if (name == extensibleAttribute) {
             qCWarning(lcShiboken, "%s",
                       qPrintable(msgUnimplementedAttributeWarning(reader, name)));
-        } else if (name == flagsAttribute()) {
+        } else if (name == flagsAttribute) {
             flagNames = attributes->takeAt(i).value().toString();
         }
     }
@@ -1654,7 +1649,7 @@ NamespaceTypeEntryPtr
             }
             result->setExtends(*extendsIt);
             attributes->removeAt(i);
-        } else if (attributeName == visibleAttribute()) {
+        } else if (attributeName == visibleAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto visibilityOpt = visibilityFromAttribute(attribute.value());
             if (!visibilityOpt.has_value()) {
@@ -1662,11 +1657,12 @@ NamespaceTypeEntryPtr
                 return nullptr;
             }
             visibility = visibilityOpt.value();
-        } else if (attributeName == generateAttribute()) {
-            if (!convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true))
+        } else if (attributeName == generateAttribute) {
+            if (!convertBoolean(attributes->takeAt(i).value(), generateAttribute, true))
                 visibility = TypeSystem::Visibility::Invisible;
-        } else if (attributeName == generateUsingAttribute()) {
-            result->setGenerateUsing(convertBoolean(attributes->takeAt(i).value(), generateUsingAttribute(), true));
+        } else if (attributeName == generateUsingAttribute) {
+            result->setGenerateUsing(convertBoolean(attributes->takeAt(i).value(),
+                                                    generateUsingAttribute, true));
         }
     }
 
@@ -1716,15 +1712,18 @@ FunctionTypeEntryPtr
     const bool hasModification = attributes->size() < oldAttributesSize;
 
     QString originalSignature;
+    QString docFile;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == signatureAttribute())
+        if (name == signatureAttribute)
             originalSignature = attributes->takeAt(i).value().toString().simplified();
+        else if (name == docFileAttribute)
+            docFile = attributes->takeAt(i).value().toString();
     }
 
     const QString signature = TypeDatabase::normalizedSignature(originalSignature);
     if (signature.isEmpty()) {
-        m_error =  msgMissingAttribute(signatureAttribute());
+        m_error =  msgMissingAttribute(signatureAttribute);
         return nullptr;
     }
 
@@ -1739,13 +1738,14 @@ FunctionTypeEntryPtr
     if (!existingType) {
         auto result = std::make_shared<FunctionTypeEntry>(name, signature, since,
                                                           currentParentTypeEntry());
+        result->setTargetLangPackage(m_defaultPackage);
+        result->setDocFile(docFile);
         applyCommonAttributes(reader, result, attributes);
         return result;
     }
 
     if (existingType->type() != TypeEntry::FunctionType) {
-        m_error = QStringLiteral("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.")
-                 .arg(name);
+        m_error = name + " expected to be a function, but isn't! Maybe it was already declared as a class or something else."_L1;
         return nullptr;
     }
 
@@ -1767,9 +1767,9 @@ TypedefEntryPtr
         m_error = u"typedef entries must be nested in namespaces or type system."_s;
         return nullptr;
     }
-    const auto sourceIndex = indexOfAttribute(*attributes, sourceAttribute());
+    const auto sourceIndex = indexOfAttribute(*attributes, sourceAttribute);
     if (sourceIndex == -1) {
-        m_error =  msgMissingAttribute(sourceAttribute());
+        m_error =  msgMissingAttribute(sourceAttribute);
         return nullptr;
     }
     const QString sourceType = attributes->takeAt(sourceIndex).value().toString();
@@ -1793,34 +1793,38 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader
     QString package = m_defaultPackage;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == streamAttribute()) {
-            ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute(), false));
-        } else if (name == privateAttribute()) {
+        if (name == streamAttribute) {
+            ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute, false));
+        } else if (name == privateAttribute) {
             ctype->setPrivate(convertBoolean(attributes->takeAt(i).value(),
-                                             privateAttribute(), false));
-        } else if (name == generateAttribute()) {
-            generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true);
-        } else if (name ==packageAttribute()) {
+                                             privateAttribute, false));
+        } else if (name == generateAttribute) {
+            generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute, true);
+        } else if (name ==packageAttribute) {
             package = attributes->takeAt(i).value().toString();
-        } else if (name == defaultSuperclassAttribute()) {
+        } else if (name == defaultSuperclassAttribute) {
             ctype->setDefaultSuperclass(attributes->takeAt(i).value().toString());
-        } else if (name == genericClassAttribute()) {
+        } else if (name == genericClassAttribute) {
             qCWarning(lcShiboken, "%s",
                       qPrintable(msgUnimplementedAttributeWarning(reader, name)));
-            const bool v = convertBoolean(attributes->takeAt(i).value(), genericClassAttribute(), false);
+            const bool v = convertBoolean(attributes->takeAt(i).value(),
+                                          genericClassAttribute, false);
             ctype->setGenericClass(v);
-        } else if (name == targetLangNameAttribute()) {
+        } else if (name == targetLangNameAttribute) {
             ctype->setTargetLangName(attributes->takeAt(i).value().toString());
-        } else if (name == u"polymorphic-base") {
-            ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString());
+        } else if (name == polymorphicBaseAttribute) {
+            const bool v = convertBoolean(attributes->takeAt(i).value(),
+                                          polymorphicBaseAttribute, false);
+            ctype->setIsPolymorphicBase(v);
         } else if (name == u"polymorphic-name-function") {
             ctype->setPolymorphicNameFunction(attributes->takeAt(i).value().toString());
         } else if (name == u"polymorphic-id-expression") {
             ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString());
-        } else if (name == copyableAttribute()) {
-            const bool v = convertBoolean(attributes->takeAt(i).value(), copyableAttribute(), false);
+        } else if (name == copyableAttribute) {
+            const bool v = convertBoolean(attributes->takeAt(i).value(),
+                                          copyableAttribute, false);
             ctype->setCopyable(v ? ComplexTypeEntry::CopyableSet : ComplexTypeEntry::NonCopyableSet);
-        } else if (name == exceptionHandlingAttribute()) {
+        } else if (name == exceptionHandlingAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value());
             if (exceptionOpt.has_value()) {
@@ -1829,7 +1833,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader
                 qCWarning(lcShiboken, "%s",
                           qPrintable(msgInvalidAttributeValue(attribute)));
             }
-        } else if (name == allowThreadAttribute()) {
+        } else if (name == allowThreadAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto allowThreadOpt = allowThreadFromAttribute(attribute.value());
             if (allowThreadOpt.has_value()) {
@@ -1843,19 +1847,25 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader
                       qPrintable(msgUnimplementedAttributeWarning(reader, name)));
         } else if (name == u"hash-function") {
             ctype->setHashFunction(attributes->takeAt(i).value().toString());
-        } else if (name == forceAbstractAttribute()) {
-            if (convertBoolean(attributes->takeAt(i).value(), forceAbstractAttribute(), false))
+        } else if (name == forceAbstractAttribute) {
+            if (convertBoolean(attributes->takeAt(i).value(), forceAbstractAttribute, false))
                 ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract);
-        } else if (name == deprecatedAttribute()) {
-            if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute(), false))
+        } else if (name == deprecatedAttribute) {
+            if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute, false))
                 ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
-        } else if (name == disableWrapperAttribute()) {
-            if (convertBoolean(attributes->takeAt(i).value(), disableWrapperAttribute(), false))
+        } else if (name == disableWrapperAttribute) {
+            if (convertBoolean(attributes->takeAt(i).value(), disableWrapperAttribute, false))
                 ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DisableWrapper);
-        } else if (name == deleteInMainThreadAttribute()) {
-            if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute(), false))
+        } else if (name == deleteInMainThreadAttribute) {
+            if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute, false))
                 ctype->setDeleteInMainThread(true);
-        } else if (name == generateFunctionsAttribute()) {
+        } else if (name == qtMetaObjectFunctionsAttribute) {
+            if (!convertBoolean(attributes->takeAt(i).value(),
+                                qtMetaObjectFunctionsAttribute, true))  {
+                ctype->setTypeFlags(ctype->typeFlags()
+                                    | ComplexTypeEntry::DisableQtMetaObjectFunctions);
+            }
+        } else if (name == generateFunctionsAttribute) {
             const auto names = attributes->takeAt(i).value();
             const auto nameList = names.split(u';', Qt::SkipEmptyParts);
             QSet<QString> nameSet;
@@ -1864,7 +1874,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader
             ctype->setGenerateFunctions(nameSet);
         } else if (name == u"target-type") {
             ctype->setTargetType(attributes->takeAt(i).value().toString());
-        }  else if (name == snakeCaseAttribute()) {
+        }  else if (name == snakeCaseAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value());
             if (snakeCaseOpt.has_value()) {
@@ -1873,7 +1883,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader
                 qCWarning(lcShiboken, "%s",
                           qPrintable(msgInvalidAttributeValue(attribute)));
             }
-        }  else if (name == isNullAttribute()) {
+        }  else if (name == isNullAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto boolCastOpt = boolCastFromAttribute(attribute.value());
             if (boolCastOpt.has_value()) {
@@ -1882,7 +1892,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader
                 qCWarning(lcShiboken, "%s",
                           qPrintable(msgInvalidAttributeValue(attribute)));
             }
-        }  else if (name == operatorBoolAttribute()) {
+        }  else if (name == operatorBoolAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto boolCastOpt = boolCastFromAttribute(attribute.value());
             if (boolCastOpt.has_value()) {
@@ -1891,7 +1901,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader
                 qCWarning(lcShiboken, "%s",
                           qPrintable(msgInvalidAttributeValue(attribute)));
             }
-        } else if (name == qtMetaTypeAttribute()) {
+        } else if (name == qtMetaTypeAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto qtMetaTypeOpt = qtMetaTypeFromAttribute(attribute.value());
             if (qtMetaTypeOpt.has_value()) {
@@ -1900,9 +1910,9 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader
                 qCWarning(lcShiboken, "%s",
                           qPrintable(msgInvalidAttributeValue(attribute)));
             }
-        } else if (name == parentManagementAttribute()) {
+        } else if (name == parentManagementAttribute) {
             const auto attribute = attributes->takeAt(i);
-            if (convertBoolean(attribute.value(), parentManagementAttribute(), false))
+            if (convertBoolean(attribute.value(), parentManagementAttribute, false))
                 ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ParentManagement);
             ComplexTypeEntry::setParentManagementEnabled(true);
         }
@@ -1956,16 +1966,16 @@ bool TypeSystemParser::parseRenameFunction(const ConditionalStreamReader &,
     QString rename;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == signatureAttribute()) {
+        if (name == signatureAttribute) {
             // Do not remove as it is needed for the type entry later on
             signature = attributes->at(i).value().toString().simplified();
-        } else if (name == renameAttribute()) {
+        } else if (name == renameAttribute) {
             rename = attributes->takeAt(i).value().toString();
         }
     }
 
     if (signature.isEmpty()) {
-        m_error = msgMissingAttribute(signatureAttribute());
+        m_error = msgMissingAttribute(signatureAttribute);
         return false;
     }
 
@@ -2021,7 +2031,7 @@ bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &,
                 return false;
             }
             mode = modeOpt.value();
-        } else if (name == formatAttribute()) {
+        } else if (name == formatAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto langOpt = languageFromAttribute(attribute.value());
             if (!langOpt.has_value()) {
@@ -2035,6 +2045,12 @@ bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &,
     QString signature = isTypeEntry(topElement) ? QString() : m_currentSignature;
     DocModification mod(mode, signature);
     mod.setFormat(lang);
+    if (hasFileSnippetAttributes(attributes)) {
+        const auto snippetOptional = readFileSnippet(attributes);
+        if (!snippetOptional.has_value())
+            return false;
+        mod.setCode(snippetOptional.value().content);
+    }
     auto &top = m_contextStack.top();
     if (isAddFunction)
         top->addedFunctions.last()->addDocModification(mod);
@@ -2056,9 +2072,9 @@ bool TypeSystemParser::parseModifyDocumentation(const ConditionalStreamReader &,
         return false;
     }
 
-    const auto xpathIndex = indexOfAttribute(*attributes, xPathAttribute());
+    const auto xpathIndex = indexOfAttribute(*attributes, xPathAttribute);
     if (xpathIndex == -1) {
-        m_error = msgMissingAttribute(xPathAttribute());
+        m_error = msgMissingAttribute(xPathAttribute);
         return false;
     }
 
@@ -2075,14 +2091,17 @@ TypeSystemTypeEntryPtr TypeSystemParser::parseRootElement(const ConditionalStrea
                                                QXmlStreamAttributes *attributes)
 {
     TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified;
+    QString subModuleOf;
+    QString namespaceBegin;
+    QString namespaceEnd;
 
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == packageAttribute()) {
+        if (name == packageAttribute) {
             m_defaultPackage = attributes->takeAt(i).value().toString();
-        } else if (name == defaultSuperclassAttribute()) {
+        } else if (name == defaultSuperclassAttribute) {
             m_defaultSuperclass = attributes->takeAt(i).value().toString();
-        } else if (name == exceptionHandlingAttribute()) {
+        } else if (name == exceptionHandlingAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value());
             if (exceptionOpt.has_value()) {
@@ -2091,7 +2110,7 @@ TypeSystemTypeEntryPtr TypeSystemParser::parseRootElement(const ConditionalStrea
                 qCWarning(lcShiboken, "%s",
                           qPrintable(msgInvalidAttributeValue(attribute)));
             }
-        } else if (name == allowThreadAttribute()) {
+        } else if (name == allowThreadAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto allowThreadOpt = allowThreadFromAttribute(attribute.value());
             if (allowThreadOpt.has_value()) {
@@ -2100,7 +2119,7 @@ TypeSystemTypeEntryPtr TypeSystemParser::parseRootElement(const ConditionalStrea
                 qCWarning(lcShiboken, "%s",
                           qPrintable(msgInvalidAttributeValue(attribute)));
             }
-        } else if (name == snakeCaseAttribute()) {
+        } else if (name == snakeCaseAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value());
             if (snakeCaseOpt.has_value()) {
@@ -2109,6 +2128,12 @@ TypeSystemTypeEntryPtr TypeSystemParser::parseRootElement(const ConditionalStrea
                 qCWarning(lcShiboken, "%s",
                           qPrintable(msgInvalidAttributeValue(attribute)));
             }
+        } else if (name == subModuleOfAttribute) {
+            subModuleOf = attributes->takeAt(i).value().toString();
+        } else if (name == "namespace-begin"_L1) {
+            namespaceBegin = attributes->takeAt(i).value().toString();
+        } else if (name == "namespace-end"_L1) {
+            namespaceEnd = attributes->takeAt(i).value().toString();
         }
     }
 
@@ -2125,9 +2150,14 @@ TypeSystemTypeEntryPtr TypeSystemParser::parseRootElement(const ConditionalStrea
     if (add) {
         moduleEntry.reset(new TypeSystemTypeEntry(m_defaultPackage, since,
                                                   currentParentTypeEntry()));
+        moduleEntry->setSubModule(subModuleOf);
     }
     moduleEntry->setCodeGeneration(m_generate);
     moduleEntry->setSnakeCase(snakeCase);
+    if (!namespaceBegin.isEmpty())
+        moduleEntry->setNamespaceBegin(namespaceBegin);
+    if (!namespaceEnd.isEmpty())
+        moduleEntry->setNamespaceEnd(namespaceEnd);
 
     if ((m_generate == TypeEntry::GenerateForSubclass ||
          m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty())
@@ -2145,10 +2175,10 @@ bool TypeSystemParser::loadTypesystem(const ConditionalStreamReader &,
     bool generateChild = true;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == nameAttribute())
+        if (name == nameAttribute)
             typeSystemName = attributes->takeAt(i).value().toString();
-        else if (name == generateAttribute())
-           generateChild = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true);
+        else if (name == generateAttribute)
+           generateChild = convertBoolean(attributes->takeAt(i).value(), generateAttribute, true);
     }
     if (typeSystemName.isEmpty()) {
             m_error = u"No typesystem name specified"_s;
@@ -2169,9 +2199,9 @@ bool TypeSystemParser::parseRejectEnumValue(const ConditionalStreamReader &,
         m_error = u"<reject-enum-value> node must be used inside a <enum-type> node"_s;
         return false;
     }
-    const auto nameIndex = indexOfAttribute(*attributes, nameAttribute());
+    const auto nameIndex = indexOfAttribute(*attributes, nameAttribute);
     if (nameIndex == -1) {
-        m_error = msgMissingAttribute(nameAttribute());
+        m_error = msgMissingAttribute(nameAttribute);
         return false;
     }
     m_currentEnum->addEnumValueRejection(attributes->takeAt(nameIndex).value().toString());
@@ -2186,7 +2216,7 @@ bool TypeSystemParser::parseReplaceArgumentType(const ConditionalStreamReader &,
         m_error = u"Type replacement can only be specified for argument modifications"_s;
         return false;
     }
-    const auto modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute());
+    const auto modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute);
     if (modifiedTypeIndex == -1) {
         m_error = u"Type replacement requires 'modified-type' attribute"_s;
         return false;
@@ -2214,7 +2244,7 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &,
     TypeSystem::Language lang = TypeSystem::NativeCode;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == classAttribute()) {
+        if (name == classAttribute) {
             const auto languageAttribute = attributes->takeAt(i);
             const auto langOpt = languageFromAttribute(languageAttribute.value());
             if (!langOpt.has_value()) {
@@ -2224,7 +2254,7 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &,
             lang = langOpt.value();
         } else if (name == u"file") {
             sourceFile = attributes->takeAt(i).value().toString();
-        } else if (name == snippetAttribute()) {
+        } else if (name == snippetAttribute) {
             snippetLabel = attributes->takeAt(i).value().toString();
         }
     }
@@ -2291,7 +2321,7 @@ bool TypeSystemParser::parseNativeToTarget(const ConditionalStreamReader &,
         return false;
     }
     CodeSnip snip;
-    if (!readFileSnippet(attributes, &snip))
+    if (!readCodeSnippet(attributes, &snip))
         return false;
     m_contextStack.top()->conversionCodeSnips.append(snip);
     return true;
@@ -2308,7 +2338,7 @@ bool TypeSystemParser::parseAddConversion(const ConditionalStreamReader &,
     QString sourceTypeName;
     QString typeCheck;
     CodeSnip snip;
-    if (!readFileSnippet(attributes, &snip))
+    if (!readCodeSnippet(attributes, &snip))
         return false;
 
     const auto &top = m_contextStack.top();
@@ -2343,7 +2373,7 @@ static bool parseIndex(const QString &index, int *result, QString *errorMessage)
     bool ok = false;
     *result = index.toInt(&ok);
     if (!ok)
-        *errorMessage = QStringLiteral("Cannot convert '%1' to integer").arg(index);
+        *errorMessage = QString::fromLatin1("Cannot convert '%1' to integer").arg(index);
     return ok;
 }
 
@@ -2378,20 +2408,20 @@ bool TypeSystemParser::parseModifyArgument(const ConditionalStreamReader &,
     bool resetAfterUse = false;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == indexAttribute()) {
+        if (name == indexAttribute) {
              index = attributes->takeAt(i).value().toString();
-        } else if (name == invalidateAfterUseAttribute()) {
+        } else if (name == invalidateAfterUseAttribute) {
             resetAfterUse = convertBoolean(attributes->takeAt(i).value(),
-                                           invalidateAfterUseAttribute(), false);
-        } else if (name == renameAttribute()) {
+                                           invalidateAfterUseAttribute, false);
+        } else if (name == renameAttribute) {
             renameTo = attributes->takeAt(i).value().toString();
-        } else if (name == pyiTypeAttribute()) {
+        } else if (name == pyiTypeAttribute) {
             pyiType = attributes->takeAt(i).value().toString();
         }
     }
 
     if (index.isEmpty()) {
-        m_error = msgMissingAttribute(indexAttribute());
+        m_error = msgMissingAttribute(indexAttribute);
         return false;
     }
 
@@ -2441,7 +2471,7 @@ bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &,
     std::optional<TypeSystem::Ownership> ownershipOpt;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == classAttribute()) {
+        if (name == classAttribute) {
             const auto classAttribute = attributes->takeAt(i);
             const auto langOpt = languageFromAttribute(classAttribute.value());
             if (!langOpt.has_value() || langOpt.value() == TypeSystem::ShellCode) {
@@ -2449,7 +2479,7 @@ bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &,
                 return false;
             }
             lang = langOpt.value();
-        } else if (name == ownershipAttribute()) {
+        } else if (name == ownershipAttribute) {
             const auto attribute = attributes->takeAt(i);
             ownershipOpt = ownershipFromFromAttribute(attribute.value());
             if (!ownershipOpt.has_value()) {
@@ -2460,7 +2490,7 @@ bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &,
     }
 
     if (!ownershipOpt.has_value()) {
-        m_error = QStringLiteral("unspecified ownership");
+        m_error = "unspecified ownership"_L1;
         return false;
     }
     auto &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods().last();
@@ -2487,9 +2517,9 @@ bool TypeSystemParser::parseRename(const ConditionalStreamReader &,
         return false;
     }
 
-    const auto toIndex = indexOfAttribute(*attributes, toAttribute());
+    const auto toIndex = indexOfAttribute(*attributes, toAttribute);
     if (toIndex == -1) {
-        m_error = msgMissingAttribute(toAttribute());
+        m_error = msgMissingAttribute(toAttribute);
         return false;
     }
     const QString renamed_to = attributes->takeAt(toIndex).value().toString();
@@ -2503,20 +2533,20 @@ bool TypeSystemParser::parseModifyField(const ConditionalStreamReader &,
     FieldModification fm;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == nameAttribute()) {
+        if (name == nameAttribute) {
             fm.setName(attributes->takeAt(i).value().toString());
-        } else if (name == removeAttribute()) {
+        } else if (name == removeAttribute) {
             fm.setRemoved(convertRemovalAttribute(attributes->takeAt(i).value()));
-        } else if (name == opaqueContainerFieldAttribute()) {
+        } else if (name == opaqueContainerFieldAttribute) {
             fm.setOpaqueContainer(convertBoolean(attributes->takeAt(i).value(),
-                                                 opaqueContainerFieldAttribute(), false));
-        }  else if (name == readAttribute()) {
-            fm.setReadable(convertBoolean(attributes->takeAt(i).value(), readAttribute(), true));
-        } else if (name == writeAttribute()) {
-            fm.setWritable(convertBoolean(attributes->takeAt(i).value(), writeAttribute(), true));
-        } else if (name == renameAttribute()) {
+                                                 opaqueContainerFieldAttribute, false));
+        }  else if (name == readAttribute) {
+            fm.setReadable(convertBoolean(attributes->takeAt(i).value(), readAttribute, true));
+        } else if (name == writeAttribute) {
+            fm.setWritable(convertBoolean(attributes->takeAt(i).value(), writeAttribute, true));
+        } else if (name == renameAttribute) {
             fm.setRenamedToName(attributes->takeAt(i).value().toString());
-        } else if (name == snakeCaseAttribute()) {
+        } else if (name == snakeCaseAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value());
             if (snakeCaseOpt.has_value()) {
@@ -2528,7 +2558,7 @@ bool TypeSystemParser::parseModifyField(const ConditionalStreamReader &,
         }
     }
     if (fm.name().isEmpty()) {
-        m_error = msgMissingAttribute(nameAttribute());
+        m_error = msgMissingAttribute(nameAttribute);
         return false;
     }
     m_contextStack.top()->fieldMods << fm;
@@ -2572,21 +2602,25 @@ bool TypeSystemParser::parseAddFunction(const ConditionalStreamReader &,
     QString returnType;
     bool staticFunction = false;
     bool classMethod = false;
+    bool pythonOverride = false;
     QString access;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == signatureAttribute()) {
+        if (name == signatureAttribute) {
             originalSignature = attributes->takeAt(i).value().toString().simplified();
         } else if (name == u"return-type") {
             returnType = attributes->takeAt(i).value().toString();
-        } else if (name == staticAttribute()) {
+        } else if (name == staticAttribute) {
             staticFunction = convertBoolean(attributes->takeAt(i).value(),
-                                            staticAttribute(), false);
-        } else if (name == classmethodAttribute()) {
+                                            staticAttribute, false);
+        } else if (name == classmethodAttribute) {
             classMethod = convertBoolean(attributes->takeAt(i).value(),
-                                            classmethodAttribute(), false);
-        } else if (name == accessAttribute()) {
+                                            classmethodAttribute, false);
+        } else if (name == accessAttribute) {
             access = attributes->takeAt(i).value().toString();
+        } else if (name == pythonOverrideAttribute) {
+            pythonOverride = convertBoolean(attributes->takeAt(i).value(),
+                                            pythonOverrideAttribute, false);
         }
     }
 
@@ -2610,6 +2644,8 @@ bool TypeSystemParser::parseAddFunction(const ConditionalStreamReader &,
 
     func->setStatic(staticFunction);
     func->setClassMethod(classMethod);
+    func->setPythonOverride(pythonOverride);
+    func->setTargetLangPackage(m_defaultPackage);
 
     // Create signature for matching modifications
     signature = TypeDatabase::normalizedSignature(originalSignature);
@@ -2651,7 +2687,7 @@ bool TypeSystemParser::parseAddPyMethodDef(const ConditionalStreamReader &,
     TypeSystemPyMethodDefEntry def;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == nameAttribute()) {
+        if (name == nameAttribute) {
             def.name = attributes->takeAt(i).value().toString();
         } else if (name == u"doc") {
             def.doc = attributes->takeAt(i).value().toString();
@@ -2690,7 +2726,7 @@ bool TypeSystemParser::parseProperty(const ConditionalStreamReader &, StackEleme
     TypeSystemProperty property;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == nameAttribute()) {
+        if (name == nameAttribute) {
             property.name = attributes->takeAt(i).value().toString();
         } else if (name == u"get") {
             property.read = attributes->takeAt(i).value().toString();
@@ -2698,10 +2734,10 @@ bool TypeSystemParser::parseProperty(const ConditionalStreamReader &, StackEleme
             property.type = attributes->takeAt(i).value().toString();
         } else if (name == u"set") {
             property.write = attributes->takeAt(i).value().toString();
-        } else if (name == generateGetSetDefAttribute()) {
+        } else if (name == generateGetSetDefAttribute) {
             property.generateGetSetDef =
                 convertBoolean(attributes->takeAt(i).value(),
-                               generateGetSetDefAttribute(), false);
+                               generateGetSetDefAttribute, false);
         }
     }
     if (!property.isValid()) {
@@ -2719,7 +2755,7 @@ bool TypeSystemParser::parseBasicModifyFunctionAttributes(QXmlStreamAttributes *
 {
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == overloadNumberAttribute()) {
+        if (name == overloadNumberAttribute) {
             int overloadNumber = TypeSystem::OverloadNumberUnset;
             if (!parseOverloadNumber(attributes->takeAt(i), &overloadNumber, &m_error))
                 return false;
@@ -2739,7 +2775,7 @@ bool TypeSystemParser::parseModifyFunctionAttributes(QXmlStreamAttributes *attri
 
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == allowThreadAttribute()) {
+        if (name == allowThreadAttribute) {
             const QXmlStreamAttribute attribute = attributes->takeAt(i);
             const auto allowThreadOpt = allowThreadFromAttribute(attribute.value());
             if (!allowThreadOpt.has_value()) {
@@ -2747,7 +2783,7 @@ bool TypeSystemParser::parseModifyFunctionAttributes(QXmlStreamAttributes *attri
                 return false;
             }
             mod->setAllowThread(allowThreadOpt.value());
-        } else if (name == exceptionHandlingAttribute()) {
+        } else if (name == exceptionHandlingAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value());
             if (!exceptionOpt.has_value()) {
@@ -2755,7 +2791,7 @@ bool TypeSystemParser::parseModifyFunctionAttributes(QXmlStreamAttributes *attri
                 return false;
             }
             mod->setExceptionHandling(exceptionOpt.value());
-        } else if (name == snakeCaseAttribute()) {
+        } else if (name == snakeCaseAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value());
             if (!snakeCaseOpt.has_value()) {
@@ -2763,9 +2799,9 @@ bool TypeSystemParser::parseModifyFunctionAttributes(QXmlStreamAttributes *attri
                 return false;
             }
             mod->setSnakeCase(snakeCaseOpt.value());
-        } else if (name == deprecatedAttribute()) {
+        } else if (name == deprecatedAttribute) {
             const bool deprecated = convertBoolean(attributes->takeAt(i).value(),
-                                                   deprecatedAttribute(), false);
+                                                   deprecatedAttribute, false);
             mod->setModifierFlag(deprecated ? FunctionModification::Deprecated
                                             : FunctionModification::Undeprecated);
         }
@@ -2796,15 +2832,15 @@ bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader
     QString rename;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == signatureAttribute()) {
+        if (name == signatureAttribute) {
             originalSignature = attributes->takeAt(i).value().toString().simplified();
-        } else if (name == accessAttribute()) {
+        } else if (name == accessAttribute) {
             access = attributes->takeAt(i).value().toString();
-        } else if (name == renameAttribute()) {
+        } else if (name == renameAttribute) {
             rename = attributes->takeAt(i).value().toString();
-        } else if (name == removeAttribute()) {
+        } else if (name == removeAttribute) {
             removed = convertRemovalAttribute(attributes->takeAt(i).value());
-        } else if (name == virtualSlotAttribute() || name == threadAttribute()) {
+        } else if (name == virtualSlotAttribute || name == threadAttribute) {
             qCWarning(lcShiboken, "%s",
                       qPrintable(msgUnimplementedAttributeWarning(reader, name)));
         }
@@ -2844,7 +2880,7 @@ bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader
         if (m == FunctionModification::NonFinal) {
             qCWarning(lcShiboken, "%s",
                       qPrintable(msgUnimplementedAttributeValueWarning(reader,
-                      accessAttribute(), access)));
+                      accessAttribute, access)));
         }
         mod.setModifierFlag(m);
     }
@@ -2891,7 +2927,7 @@ bool TypeSystemParser::parseReferenceCount(const ConditionalStreamReader &reader
     ReferenceCount rc;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == actionAttribute()) {
+        if (name == actionAttribute) {
             const QXmlStreamAttribute attribute = attributes->takeAt(i);
             const auto actionOpt = referenceCountFromAttribute(attribute.value());
             if (!actionOpt.has_value()) {
@@ -2928,11 +2964,11 @@ bool TypeSystemParser::parseParentOwner(const ConditionalStreamReader &,
     ArgumentOwner ao;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == indexAttribute()) {
+        if (name == indexAttribute) {
             const QString index = attributes->takeAt(i).value().toString();
             if (!parseArgumentIndex(index, &ao.index, &m_error))
                 return false;
-        } else if (name == actionAttribute()) {
+        } else if (name == actionAttribute) {
             const auto action = attributes->takeAt(i);
             const auto actionOpt = argumentOwnerActionFromAttribute(action.value());
             if (!actionOpt.has_value()) {
@@ -2946,46 +2982,62 @@ bool TypeSystemParser::parseParentOwner(const ConditionalStreamReader &,
     return true;
 }
 
-bool TypeSystemParser::readFileSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip)
+std::optional<TypeSystemParser::Snippet>
+    TypeSystemParser::readFileSnippet(QXmlStreamAttributes *attributes)
 {
-    QString fileName;
-    QString snippetLabel;
+    Snippet result;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == u"file") {
-            fileName = attributes->takeAt(i).value().toString();
-        } else if (name == snippetAttribute()) {
-            snippetLabel = attributes->takeAt(i).value().toString();
+        if (name == fileAttribute) {
+            result.fileName = attributes->takeAt(i).value().toString();
+        } else if (name == snippetAttribute) {
+            result.snippetLabel = attributes->takeAt(i).value().toString();
         }
     }
-    if (fileName.isEmpty())
-        return true;
-    const QString resolved = m_context->db->modifiedTypesystemFilepath(fileName, m_currentPath);
+    if (result.fileName.isEmpty()) {
+        m_error = "Snippet missing file name"_L1;
+        return std::nullopt;
+    }
+    const QString resolved = m_context->db->modifiedTypesystemFilepath(result.fileName,
+                                                                       m_currentPath);
     if (!QFile::exists(resolved)) {
         m_error = u"File for inject code not exist: "_s
-            + QDir::toNativeSeparators(fileName);
-        return false;
+                  + QDir::toNativeSeparators(result.fileName);
+        return std::nullopt;
     }
     QFile codeFile(resolved);
     if (!codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
         m_error = msgCannotOpenForReading(codeFile);
-        return false;
+        return std::nullopt;
     }
-    const auto codeOptional = extractSnippet(QString::fromUtf8(codeFile.readAll()), snippetLabel);
+    const auto contentOptional = extractSnippet(QString::fromUtf8(codeFile.readAll()),
+                                                result.snippetLabel);
     codeFile.close();
-    if (!codeOptional.has_value()) {
-        m_error = msgCannotFindSnippet(resolved, snippetLabel);
-        return false;
+    if (!contentOptional.has_value()) {
+        m_error = msgCannotFindSnippet(resolved, result.snippetLabel);
+        return std::nullopt;
     }
+    result.content = contentOptional.value();
+    return result;
+}
+
+bool TypeSystemParser::readCodeSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip)
+{
+    if (!hasFileSnippetAttributes(attributes))
+        return true; // Expecting inline content.
+    const auto snippetOptional = readFileSnippet(attributes);
+    if (!snippetOptional.has_value())
+        return false;
+    const auto snippet = snippetOptional.value();
 
-    QString source = fileName;
-    if (!snippetLabel.isEmpty())
-        source += u" ("_s + snippetLabel + u')';
+    QString source = snippet.fileName;
+    if (!snippet.snippetLabel.isEmpty())
+        source += " ("_L1 + snippet.snippetLabel + u')';
     QString content;
     QTextStream str(&content);
     str << "// ========================================================================\n"
            "// START of custom code block [file: "
-        << source << "]\n" << codeOptional.value()
+        << source << "]\n" << snippet.content
         << "// END of custom code block [file: " << source
         << "]\n// ========================================================================\n";
     snip->addCode(content);
@@ -3007,11 +3059,11 @@ bool TypeSystemParser::parseInjectCode(const ConditionalStreamReader &,
     TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionBeginning;
     TypeSystem::Language lang = TypeSystem::TargetLangCode;
     CodeSnip snip;
-    if (!readFileSnippet(attributes, &snip))
+    if (!readCodeSnippet(attributes, &snip))
         return false;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == classAttribute()) {
+        if (name == classAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto langOpt = languageFromAttribute(attribute.value());
             if (!langOpt.has_value()) {
@@ -3019,7 +3071,7 @@ bool TypeSystemParser::parseInjectCode(const ConditionalStreamReader &,
                 return false;
             }
             lang = langOpt.value();
-        } else if (name == positionAttribute()) {
+        } else if (name == positionAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto positionOpt = codeSnipPositionFromAttribute(attribute.value());
             if (!positionOpt.has_value()) {
@@ -3060,9 +3112,9 @@ bool TypeSystemParser::parseInclude(const ConditionalStreamReader &,
     Include::IncludeType location = Include::IncludePath;
     for (auto i = attributes->size() - 1; i >= 0; --i) {
         const auto name = attributes->at(i).qualifiedName();
-        if (name == fileNameAttribute()) {
+        if (name == fileNameAttribute) {
             fileName = attributes->takeAt(i).value().toString();
-        } else if (name == locationAttribute()) {
+        } else if (name == locationAttribute) {
             const auto attribute = attributes->takeAt(i);
             const auto locationOpt = locationFromAttribute(attribute.value());
             if (!locationOpt.has_value()) {
@@ -3092,9 +3144,9 @@ bool TypeSystemParser::parseInclude(const ConditionalStreamReader &,
 bool TypeSystemParser::parseSystemInclude(const ConditionalStreamReader &,
                                           QXmlStreamAttributes *attributes)
 {
-    const auto index = indexOfAttribute(*attributes, fileNameAttribute());
+    const auto index = indexOfAttribute(*attributes, fileNameAttribute);
     if (index == -1) {
-        m_error = msgMissingAttribute(fileNameAttribute());
+        m_error = msgMissingAttribute(fileNameAttribute);
         return false;
     }
     TypeDatabase::instance()->addForceProcessSystemInclude(attributes->takeAt(index).value().toString());
@@ -3115,9 +3167,9 @@ TemplateInstance *
                    "conversion-rule, native-to-target or add-conversion tags."_s;
         return nullptr;
     }
-    const auto nameIndex = indexOfAttribute(*attributes, nameAttribute());
+    const auto nameIndex = indexOfAttribute(*attributes, nameAttribute);
     if (nameIndex == -1) {
-        m_error = msgMissingAttribute(nameAttribute());
+        m_error = msgMissingAttribute(nameAttribute);
         return nullptr;
     }
     return new TemplateInstance(attributes->takeAt(nameIndex).value().toString());
@@ -3136,7 +3188,7 @@ bool TypeSystemParser::parseReplace(const ConditionalStreamReader &,
         const auto name = attributes->at(i).qualifiedName();
         if (name == u"from")
             from = attributes->takeAt(i).value().toString();
-        else if (name == toAttribute())
+        else if (name == toAttribute)
             to = attributes->takeAt(i).value().toString();
     }
     m_templateInstance->addReplaceRule(from, to);
@@ -3192,12 +3244,12 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack
     VersionRange versionRange;
     for (auto i = attributes.size() - 1; i >= 0; --i) {
         const auto name = attributes.at(i).qualifiedName();
-        if (name == sinceAttribute()) {
+        if (name == sinceAttribute) {
             if (!parseVersion(attributes.takeAt(i).value().toString(),
                               m_defaultPackage, &versionRange.since, &m_error)) {
                 return false;
             }
-        } else if (name == untilAttribute()) {
+        } else if (name == untilAttribute) {
             if (!parseVersion(attributes.takeAt(i).value().toString(),
                               m_defaultPackage, &versionRange.until, &m_error)) {
                 return false;
@@ -3244,11 +3296,11 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack
     if (isTypeEntry(element)) {
         QString name;
         if (element != StackElement::FunctionTypeEntry) {
-            const auto nameIndex = indexOfAttribute(attributes, nameAttribute());
+            const auto nameIndex = indexOfAttribute(attributes, nameAttribute);
             if (nameIndex != -1) {
                 name = attributes.takeAt(nameIndex).value().toString();
             } else if (element != StackElement::EnumTypeEntry) { // anonymous enum?
-                m_error = msgMissingAttribute(nameAttribute());
+                m_error = msgMissingAttribute(nameAttribute);
                 return false;
             }
         }
@@ -3261,7 +3313,7 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack
 
         if (m_context->db->hasDroppedTypeEntries()) {
             const QString identifier = element == StackElement::FunctionTypeEntry
-                ? attributes.value(signatureAttribute()).toString().simplified() : name;
+                ? attributes.value(signatureAttribute).toString().simplified() : name;
             if (shouldDropTypeEntry(m_context->db, m_contextStack, identifier)) {
                 m_currentDroppedEntryDepth = 1;
                 if (ReportHandler::isDebug(ReportHandler::SparseDebug)) {
@@ -3293,7 +3345,7 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack
 
         if (element == StackElement::EnumTypeEntry) {
             const auto enumIdentifiedByIndex =
-                indexOfAttribute(attributes, enumIdentifiedByValueAttribute());
+                indexOfAttribute(attributes, enumIdentifiedByValueAttribute);
             const QString identifiedByValue = enumIdentifiedByIndex != -1
                 ? attributes.takeAt(enumIdentifiedByIndex).value().toString() : QString();
             if (name.isEmpty()) {
@@ -3440,10 +3492,10 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack
 
             const auto topParent = m_stack.value(m_stack.size() - 3, StackElement::None);
             if (isTypeEntry(topParent)) {
-                const auto replaceIndex = indexOfAttribute(attributes, replaceAttribute());
+                const auto replaceIndex = indexOfAttribute(attributes, replaceAttribute);
                 const bool replace = replaceIndex == -1
                     || convertBoolean(attributes.takeAt(replaceIndex).value(),
-                                      replaceAttribute(), true);
+                                      replaceAttribute, true);
                 auto customConversion = CustomConversion::getCustomConversion(top->entry);
                 if (!customConversion) {
                     m_error = msgMissingCustomConversion(top->entry);
@@ -3470,7 +3522,7 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack
                 return false;
             break;
         case StackElement::SuppressedWarning: {
-            const auto textIndex = indexOfAttribute(attributes, textAttribute());
+            const auto textIndex = indexOfAttribute(attributes, textAttribute);
             if (textIndex == -1) {
                 qCWarning(lcShiboken) << "Suppressed warning with no text specified";
             } else {
@@ -3559,9 +3611,9 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack
                 return false;
             break;
         case StackElement::Template: {
-            const auto nameIndex = indexOfAttribute(attributes, nameAttribute());
+            const auto nameIndex = indexOfAttribute(attributes, nameAttribute);
             if (nameIndex == -1) {
-                m_error = msgMissingAttribute(nameAttribute());
+                m_error = msgMissingAttribute(nameAttribute);
                 return false;
             }
             m_templateEntry.reset(new TemplateEntry(attributes.takeAt(nameIndex).value().toString()));
index ebec00c2c82c40031ce558e3c8a47f3c3942926b..4d9d4fd926209c2e80d902edea2ce0ba9e3d129a 100644 (file)
@@ -15,6 +15,7 @@
 #include <QtCore/QScopedPointer>
 
 #include <memory>
+#include <optional>
 
 QT_FORWARD_DECLARE_CLASS(QVersionNumber)
 QT_FORWARD_DECLARE_CLASS(QXmlStreamAttributes)
@@ -146,6 +147,13 @@ public:
     QString errorString() const { return m_error; }
 
 private:
+    struct Snippet
+    {
+        QString content;
+        QString fileName;
+        QString snippetLabel;
+    };
+
     bool parseXml(ConditionalStreamReader &reader);
     bool setupSmartPointerInstantiations();
     bool startElement(const ConditionalStreamReader &reader, StackElement element);
@@ -248,7 +256,8 @@ private:
                               QXmlStreamAttributes *);
      bool parseParentOwner(const ConditionalStreamReader &, StackElement topElement,
                            QXmlStreamAttributes *);
-     bool readFileSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip);
+     std::optional<Snippet> readFileSnippet(QXmlStreamAttributes *attributes);
+     bool readCodeSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip);
      bool parseInjectCode(const ConditionalStreamReader &, StackElement topElement, QXmlStreamAttributes *);
      bool parseInclude(const ConditionalStreamReader &, StackElement topElement,
                        const TypeEntryPtr &entry, QXmlStreamAttributes *);
index bd69058d257623146c7d21da0468536ea2a5feff..9b9670696a73a7eba66ad12e1227b61f23d411ee 100644 (file)
@@ -5,6 +5,7 @@
 #define TYPESYSTEMTYPEENTRY_H
 
 #include "typesystem.h"
+#include "modifications_typedefs.h"
 #include "typesystem_enums.h"
 #include "typesystem_typedefs.h"
 
@@ -23,6 +24,15 @@ public:
     CodeSnipList &codeSnips();
     void addCodeSnip(const CodeSnip &codeSnip);
 
+    QString subModuleOf() const;
+    void setSubModule(const QString &);
+
+    const QString &namespaceBegin() const;
+    void setNamespaceBegin(const QString &n);
+
+    const QString &namespaceEnd() const;
+    void setNamespaceEnd(const QString &n);
+
 protected:
     explicit TypeSystemTypeEntry(TypeEntryPrivate *d);
 };
index c5f361c91fd5081e539bfc83db2fca62f97a20f1..5a9a26913fd7f445c6976da02d37cadca9e0c631 100644 (file)
@@ -139,7 +139,8 @@ QString LibXmlXQuery::doEvaluate(const QString &xPathExpression, QString *errorM
 
 std::shared_ptr<XQuery> libXml_createXQuery(const QString &focus, QString *errorMessage)
 {
-    XmlDocUniquePtr doc(xmlParseFile(QFile::encodeName(focus).constData()));
+    XmlDocUniquePtr doc(xmlReadFile(QFile::encodeName(focus).constData(),
+                        "utf-8", XML_PARSE_NOENT));
     if (!doc) {
         *errorMessage = u"libxml2: Cannot set focus to "_s + QDir::toNativeSeparators(focus);
         return {};
@@ -154,20 +155,22 @@ std::shared_ptr<XQuery> libXml_createXQuery(const QString &focus, QString *error
 
 // XSLT transformation
 
-static const char xsltPrefix[] = R"(<?xml version="1.0" encoding="UTF-8" ?>
+static constexpr auto xsltPrefix = R"(<?xml version="1.0" encoding="UTF-8" ?>
     <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-)";
+)"_L1;
 
 QString libXslt_transform(const QString &xml, QString xsl, QString *errorMessage)
 {
     ensureInitialized();
     // Read XML data
     if (!xsl.startsWith(u"<?xml")) {
-        xsl.prepend(QLatin1StringView(xsltPrefix));
+        xsl.prepend(xsltPrefix);
         xsl.append(u"</xsl:transform>"_s);
     }
     const QByteArray xmlData = xml.toUtf8();
-    XmlDocUniquePtr xmlDoc(xmlParseMemory(xmlData.constData(), xmlData.size()));
+
+    XmlDocUniquePtr xmlDoc(xmlReadMemory(xmlData.constData(), int(xmlData.size()),
+                                         "", "utf-8", XML_PARSE_NOENT));
     if (!xmlDoc) {
         *errorMessage = u"xmlParseMemory() failed for XML."_s;
         return xml;
index 1a46e5b265b9694f18d4cab505d24592fb0999cd..8bc0661023f984f271c9cdfbbb2d97518a426a7c 100644 (file)
@@ -206,7 +206,7 @@ macro(get_python_extension_suffix)
         # it is unable to set Python_CONFIG i.e. find `python3-config` script
         # This workaround sets the Python_SOABI manually for this platform.
         if(CMAKE_SYSTEM_NAME STREQUAL "Android" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a")
-            set(Python_SOABI "cpython-310}")
+            set(Python_SOABI "cpython-311}")
         endif()
         if(NOT Python_SOABI)
             message(FATAL_ERROR "Python_SOABI variable is empty.")
@@ -257,7 +257,7 @@ macro(shiboken_check_if_limited_api)
                 libs = r'${Python_LIBRARIES}'
                 libs = libs.split(';')
                 for lib in libs:
-                    if '\\\\' in lib and Path(lib).is_file():
+                    if ('\\\\' in lib or '/' in lib) and Path(lib).is_file():
                         lib = Path(lib)
                         prefix = lib.parent
                         py = lib.name
index f174a6c523a02f2e9b56091c1e96e13fef26b42b..08c4646c62bd6fdf05aa071cf55a25741c42f143 100644 (file)
@@ -1,3 +1,17 @@
+.text-center {
+  text-align: center !important;
+}
+
+.text-center img {
+    padding-top: 10px;
+    height: 70px !important;
+}
+
+.cover-img img {
+  object-fit: cover;
+  height: 50%;
+}
+
 /* Tables */
 .section .docutils.container td {
     float:left;
@@ -40,3 +54,47 @@ table.docutils td ul > li {
   position:relative;
   overflow:visible
 }
+
+/* We cannot put a :download:`....` command inside
+ * a sphinx-design button, so we add some properties from the button
+ * to the download class to mimic it */
+code.download {
+  text-align: center;
+  color: var(--color-brand-primary);
+  display: block;
+  border-color: transparent;
+  background-color: transparent;
+  border: 1px solid var(--color-brand-primary) !important;
+  border-radius: 0.25rem;
+  font-size: 1rem;
+  font-weight: 400;
+  vertical-align: middle;
+  padding: .375rem .75rem;
+  user-select: none;
+  line-height: 1.5;
+  transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
+}
+
+code.download:hover {
+  color: white;
+  background-color: var(--color-brand-primary);
+  border-color: var(--color-brand-primary);
+  text-decoration: none;
+  padding: .375rem .75rem;
+}
+
+dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple):first-child > dt {
+  font-size: +2.25rem;
+  font-weight: 700;
+  color: #ff00dd;
+}
+
+.theme-toggle svg{
+  width: +1.25rem;
+  height: +2.25rem;
+}
+
+.sd-card-title code span {
+  font-size: +1rem;
+  color: var(--color-brand-primary);
+}
index 7316125e5b7405f646f8d4f4c5a65b9d23747245..e3575bc061a510717f77688170c31a2c260cd06d 100644 (file)
@@ -12,3 +12,12 @@ C++ examples
         :link: ../../examples/example_samplebinding_samplebinding.html
         :img-top: ../images/icecream.png
 
+    .. grid-item-card:: Scriptable Application
+        :class-item: cover-img
+        :link: ../../examples/example_scriptableapplication_scriptableapplication.html
+        :img-top: ../../../_images/example_no_image.png
+
+    .. grid-item-card:: Widget Binding
+        :class-item: cover-img
+        :link: ../../examples/example_widgetbinding_widgetbinding.html
+        :img-top: ../../../_images/example_no_image.png
index db842134b858905156bdfb3fc4e2fe3caaadb4df..68f96dded11e7804ef32435118b0d9ebd1bee9f3 100644 (file)
@@ -88,6 +88,18 @@ Documentation
 
             Examples
 
+    .. grid-item-card::
+        :class-item: text-center
+
+        Generating Python stub files.
+        +++
+        .. button-ref:: shiboken-genpyi
+            :color: primary
+            :outline:
+            :expand:
+
+            shiboken6-genpyi
+
     .. grid-item-card::
         :class-item: text-center
 
@@ -109,4 +121,5 @@ Documentation
    shibokenmodule.rst
    typesystem.rst
    examples/index.rst
+   shiboken-genpyi.rst
    considerations.rst
diff --git a/sources/shiboken6/doc/shiboken-genpyi.rst b/sources/shiboken6/doc/shiboken-genpyi.rst
new file mode 100644 (file)
index 0000000..44d0edb
--- /dev/null
@@ -0,0 +1,32 @@
+.. _shiboken6-genpyi:
+
+shiboken6-genpyi
+================
+
+`shiboken6-genpyi` is a command line tool to generate Python stub files
+(.pyi) for any shiboken binding-based module (not just PySide). Stub
+files define signatures of all classes, methods (including overloads),
+constants and enums of a module. Signatures also contain type hints.
+This helps your module integrate with Python type checkers and IDEs.
+For example, if you use any function from your module, your IDE's
+function lookup feature will show you the function signature and its
+parameters and return value including types.
+
+
+Usage
+-----
+
+To generate stub files for a module, run the following command:
+
+.. code-block:: bash
+
+    shiboken6-genpyi <module_names> [OPTIONS]
+
+where `<module_names>` is a space-separated list of module names (the
+modules must be importable from the working directory) and where
+`[OPTIONS]` can be one of the following:
+
+* **--quiet**: Run the tool quietly without output to stdout.
+* **--outpath <output_dir>**: Specify the output directory for the
+  generated stub files. If not specified, the stub files are generated
+  in the location of the module binary.
index b31efbcd139bc4d20de8bb3abcb820c1142a1c7c..2f1c6d166ca7208275cb327222f450fa43a38444 100644 (file)
@@ -116,6 +116,15 @@ To import the module:
 
     This method should be used **only** for debug purposes by developers.
 
+ .. function:: dumpTypeGraph(file_name)
+
+    Dumps the inheritance graph of the types existing in libshiboken
+    to ``.dot`` file for use with `Graphviz <https://graphviz.org/>`_.
+
+.. function:: dumpWrapperMap()
+
+    Dumps the map of wrappers existing in libshiboken to standard error.
+
  .. py:class:: VoidPtr(address, size = -1, writeable = 0)
 
      :param address: (PyBuffer, SbkObject, int, VoidPtr)
diff --git a/sources/shiboken6/doc/typediscovery.rst b/sources/shiboken6/doc/typediscovery.rst
new file mode 100644 (file)
index 0000000..76d3adf
--- /dev/null
@@ -0,0 +1,145 @@
+.. _typediscovery:
+
+**************
+Type Discovery
+**************
+
+When converting objects which are part of a class hierarchy from a pointer to a
+base class, it is expected to get the Python type of the actual, most derived
+type, as opposed to C++ which requires a cast for this:
+
+.. code-block:: python
+
+    def event(self, event):
+        if event.type() == QEvent.Type.MousePress:
+            self.do_things(event.position())
+    ...
+
+
+.. code-block:: c++
+
+    bool event(QEvent *event) override
+    {
+        if (event->type() == QEvent::MousePress) {
+            auto *mouseEvent = static_cast<QMouseEvent *>(event);
+            doThings(mouseEvent->position());
+        ...
+    }
+
+The process of determining the type of the event is called `type discovery`.
+
+Shiboken generates code to automatically detect the type. First, it tries to
+find a converter for the name obtained by ``typeid(*pointer).name()``. This
+should normally work as this name is registered by the binding. If that fails,
+it starts walking a type inheritance graph built up in libshiboken to find the
+most derived class by using a cast function (``dynamic_cast<>`` by default) to
+check.
+
+For normal class hierarchies with virtual destructors, no special handling
+is required since ``typeid()`` usually detects the proper class name.
+
+Multiple inheritance
+====================
+
+In case of multiple inheritance in C++, the conversion to the derived class is
+not done in case it is not a single-line direct inheritance. For example, in
+Qt, the class ``QWidget`` inherits both ``QObject`` (base of the ``QObject``
+hierarchy) and ``QPaintDevice``.
+
+When calling a function returning a ``QPaintDevice *``, for example
+``QPainter.device()``, a Python type representing ``QPaintDevice`` is returned
+instead of the underlying widget type. This restriction exists because the
+underlying pointer in C++ is a pointer to a ``QPaintDevice *`` and differs from
+the pointer to the ``QWidget``.
+
+Hierarchies of classes with non-virtual destructors
+===================================================
+
+There are some hierarchies of value-ish C++ classes that do not have virtual
+destructors. This makes type discovery based on ``typeid()`` and
+``dynamic_cast<>`` impossible.
+
+Examples in Qt are the ``QStyleOption``-derived or the ``QGradient``
+-derived classes.
+
+For such classes, some attributes need to be specified on the type entries:
+
+Primarily, a :ref:`polymorphic-id-expression` attribute
+must be specified to be used as a check replacing ``dynamic_cast<>``.
+
+In addition, a :ref:`polymorphic-name-function` attribute can be specified.
+This replaces the type name guess obtained by ``typeid()`` and is mainly a hint
+to speed things up by skipping the checks for each type in the inheritance
+graph.
+
+A :ref:`polymorphic-base` attribute identifies the base class of a hierarchy.
+It should be given in case the base class inherits from another class to
+prevent the logic from going below the base class.
+
+Using type discovery attributes for class hierarchies with virtual destructors
+==============================================================================
+
+It is possible to use :ref:`polymorphic-id-expression` and
+:ref:`polymorphic-name-function` for normal class hierarchies with virtual
+destructors as well since they basically replace ``typeid()`` and
+``dynamic_cast<>``. This makes sense if expressions can be specified that are
+faster than the checks on virtual tables.
+
+Specifying :ref:`polymorphic-base` can also make sense for generating special
+cast functions in case of multiple inheritance. For example, in Qt,
+``QWindow``, ``QLayout``, ``QWidget`` are base classes of hierarchies. Since
+they all inherit from ``QObject``, indicating the base classes prevents
+the logic from using ``QObject`` as a base class.
+
+.. _typediscovery-attributes:
+
+Type discovery attributes reference
+===================================
+
+The following attributes related to type discovery may be be specified on the
+:ref:`object-type` or :ref:`value-type` elements:
+
+.. _polymorphic-id-expression:
+
+polymorphic-id-expression
++++++++++++++++++++++++++
+
+The **polymorphic-id-expression** attribute specifies an expression checking
+whether a base class pointer is of the matching type. For example, in a
+``virtual eventHandler(BaseEvent *e)`` function, this is used to construct a
+Python wrapper matching the derived class (for example, a ``MouseEvent`` or
+similar). The attribute value may contain placeholders:
+
+%1
+    Fully qualified class name
+
+%B
+    Fully qualified name of the base class (found by base class
+    search or as indicated by **polymorphic-base**).
+
+To check for a class inheriting ``BaseEvent``, specify:
+
+.. code-block:: xml
+
+        <object-type name="MouseEvent"
+                     polymorphic-id-expression="%B-&gt;type() == BaseEvent::MouseEvent"/>
+
+.. _polymorphic-name-function:
+
+polymorphic-name-function
++++++++++++++++++++++++++
+
+The **polymorphic-name-function** attribute specifies the name of a function
+returning the type name of a derived class on the base class type entry.
+Normally, ``typeid(ptr).name()`` is used for this.
+
+The function is expected to return ``const char *``.
+
+.. _polymorphic-base:
+
+polymorphic-base
+++++++++++++++++
+
+The boolean **polymorphic-base** attribute indicates whether the class is the
+base class of a class hierarchy. It is used for the *%B* placeholder in
+**polymorphic-id-expression** and for cast operations in multiple inheritance.
index e1e4fdda2c3d56373f2b875c9bbf5cea8041dda9..26f929801630c88661e2a3dd01d90fc54521473c 100644 (file)
@@ -65,3 +65,4 @@ Extra options and Python caveats
 
    typesystem_solving_compilation.rst
    typesystem_specialfunctions.rst
+   typediscovery.rst
index d0a5a0390ef475de65dd548628ae689051be47e4..03d5f4b16c5ae3db71cca212fecd11ef78377597 100644 (file)
@@ -74,6 +74,9 @@ function.
 |               |shell |declaration|Used only for virtual functions. This code is injected at the |
 |               |      |           |top.                                                          |
 |               |      +-----------+--------------------------------------------------------------+
+|               |      |override   |Used only for virtual functions. The code is injected before  |
+|               |      |           |the code calling the Python override.                         |
+|               |      +-----------+--------------------------------------------------------------+
 |               |      |beginning  |Used only for virtual functions. The code is injected when the|
 |               |      |           |function does not has a Python implementation, then the code  |
 |               |      |           |is inserted before c++ call                                   |
index 7bdabc49cbf7bd3afe6c41d9a477457396420396..ab6fba93099394e78a5eda94af78c79c9148ca3e 100644 (file)
@@ -233,61 +233,3 @@ Variables & Functions
 **%CHECKTYPE[CPPTYPE]**
   Replaced by a |project| type checking function for a Python variable.
   The C++ type is indicated by ``CPPTYPE``.
-
-
-.. _oldconverters:
-
-Converting The Old Converters
-=============================
-
-If you use |project| for your bindings, and has defined some type conversions
-using the ``Shiboken::Converter`` template, then you must update your converters
-to the new scheme.
-
-Previously your conversion rules were declared in one line, like this:
-
-
-.. code-block:: xml
-
-    <primitive-type name="Complex" target-lang-api-name="PyComplex">
-      <include file-name="complex.h" location="global"/>
-      <conversion-rule file="complex_conversions.h"/>
-    </primitive-type>
-
-
-And implemented in a separate C++ file, like this:
-
-
-.. code-block:: c++
-
-    namespace Shiboken {
-    template<> struct Converter<Complex>
-    {
-        static inline bool checkType(PyObject* pyObj) {
-            return PyComplex_Check(pyObj);
-        }
-        static inline bool isConvertible(PyObject* pyObj) {
-            return PyComplex_Check(pyObj);
-        }
-        static inline PyObject* toPython(void* cppobj) {
-            return toPython(*reinterpret_cast<Complex*>(cppobj));
-        }
-        static inline PyObject* toPython(const Complex& cpx) {
-            return PyComplex_FromDoubles(cpx.real(), cpx.imag());
-        }
-        static inline Complex toCpp(PyObject* pyobj) {
-            double real =  PyComplex_RealAsDouble(pyobj);
-            double imag =  PyComplex_ImagAsDouble(pyobj);
-            return Complex(real, imag);
-        }
-    };
-    }
-
-
-In this case, the parts of the implementation that will be used in the new
-conversion-rule are the ones in the two last method
-``static inline PyObject* toPython(const Complex& cpx)`` and
-``static inline Complex toCpp(PyObject* pyobj)``. The ``isConvertible`` method
-is gone, and the ``checkType`` is now an attribute of the :ref:`add-conversion <add-conversion>`
-tag. Refer back to the first example in this page and you will be able to
-correlate the above template with the new scheme of conversion rule definition.
index 504d2017d1c095ccc45cf3240ba277b621dfd532..4e7d18b993942531068badb8cdcb2599a1dfee36 100644 (file)
@@ -11,7 +11,8 @@ documentation. This node is a child of the :ref:`object-type`,
 .. code-block:: xml
 
      <value-type>
-         <inject-documentation mode="append | prepend | replace" format="native | target" >
+         <inject-documentation mode="append | prepend | replace" format="native | target"
+                               file="[file]" snippet="[label]">
              // the documentation
          </inject-code>
      </value-type>
@@ -24,8 +25,18 @@ occur and it accepts the following values:
 * native: Before XML<->Backend transformation occur, so the injected code *must* be a valid XML.
 * target: After XML<->Backend transformation occur, so the injected code *must* be a valid backend format.
 
+The optional ``file`` attribute specifies the file name
+(see :ref:`external-snippets`).
+
+The optional ``snippet`` attribute specifies the snippet label
+(see :ref:`external-snippets`).
+
 At the moment the only supported backend is Sphinx.
 
+If the injected documentation contains a Sphinx function directive, no
+directive will be auto-generated. This can be used to add parameter
+documentation to added functions.
+
 modify-documentation
 ^^^^^^^^^^^^^^^^^^^^
 
index 54792e494c10e103325b46313a04401f03e578c3..e024cdf0002fae3d6446b522f41673898cca159f 100644 (file)
@@ -84,8 +84,8 @@ placeholders.
 Using Snippets From External Files
 ==================================
 
-Code snippets can also be retrieved from external files found in the
-typesystem search path (see :ref:`typesystem-paths`).
+Code or documentation snippets can also be retrieved from external
+files found in the typesystem search path (see :ref:`typesystem-paths`).
 
 .. code-block:: xml
 
@@ -282,6 +282,7 @@ logic. This can be done using the :ref:`inject-code` node.
                        access="public | protected"
                        overload-number="number"
                        static="yes | no" classmethod="yes | no"
+                       python-override ="yes | no"
                        since="..."/>
      </object-type>
 
@@ -320,6 +321,10 @@ within the `signature` field
 
 See :ref:`sequence-protocol` for adding the respective functions.
 
+The *optional* attribute ``python-override`` indicates a special type
+of added function, a python-override that will be generated into
+the native wrapper (see :ref:`modifying-virtual-functions`).
+
 .. _declare-function:
 
 declare-function
@@ -500,3 +505,52 @@ configuration (see also option :ref:`drop-type-entries`) intended
 for building several configurations from one generated source tree,
 but still requires listing the correct source files in the
 ``CMakeLists.txt`` file.
+
+.. _modifying-virtual-functions:
+
+Modifying virtual functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Some C++ virtual functions are unsuitable for Python bindings:
+
+.. code-block:: c
+
+    virtual void getInt(int *result) const;
+
+In that case, you would modify it to return the integer instead (or a tuple
+in case of several out-parameters):
+
+.. code-block:: c
+
+    virtual int getInt() const;
+
+For the binding itself, use the common argument modifications (removing
+arguments, modifying return types with injected code snippets) to modify the
+signature.
+
+To make it possible to reimplement the function in Python with the modified
+signature, add a ``python-override`` function with that signature, using an
+arbitrary name for disambiguation:
+
+.. code-block:: xml
+
+       <add-function signature="getIntPyOverride()"
+                     return-type="int" python-override="true"/>
+
+This causes a static function performing the call into Python for the override
+to be generated into the native wrapper.
+
+In the existing virtual function, inject a code snippet at the ``shell`` /
+``override`` position which calls the newly added function. The first 2
+arguments are the `Global interpreter lock handle` (``Shiboken::GilState``) and
+the Python method determined by the override check (``PyObject *``). The
+snippet then converts the arguments and return values and returns after that:
+
+.. code-block:: xml
+
+       <modify-function signature="getInt(int*)const">
+           <inject-code class="shell" position="override">
+           *result = getIntPyOverride(gil, pyOverride.object());
+           return;
+           </inject-code>
+       </modify-function>
index 406d51650892ca7093b2ea4751edec94ec9ec09f..f65b79bb485cf7701ba479c97296bb6e8cbeaf94 100644 (file)
@@ -43,14 +43,21 @@ It can have a number of attributes, described below.
 
 .. code-block:: xml
 
-    <typesystem package="..." default-superclass="..." allow-thread="..."
-                exception-handling="..." snake-case="yes | no | both" >
+    <typesystem package="..."
+                submodule-of="..."
+                allow-thread="..."
+                exception-handling="..."
+                snake-case="yes | no | both"
+                namespace-begin="..."
+                namespace-end="..." >
     </typesystem>
 
 The **package** attribute is a string describing the package to be used,
 e.g. "QtCore".
-The *optional* **default-superclass** attribute is the canonical C++ base class
-name of all objects, e.g., "object".
+
+The *optional* **submodule-of** attribute specifies the name of a module to
+which the module is added as a sub-module. This requires adapting the
+installation directory of the module accordingly.
 
 The *optional* attributes **allow-thread** and **exception-handling**
 specify the default handling for the corresponding function modification
@@ -72,6 +79,13 @@ limitations to this though:
   exist (as is the case for example for ``QFileInfo::exists()``),
   the snake case name must be used.
 
+The *optional* **namespace-begin** and **namespace-end** attributes will be
+generated around the forward declarations in the module header. This is
+intended for libraries which can optionally use inline namespaces
+to allow for linking several versions of them together.
+For example, for *Qt*, one would specify ``QT_BEGIN_NAMESPACE``,
+``QT_END_NAMESPACE``, respectively.
+
 .. _load-typesystem:
 
 load-typesystem
@@ -139,8 +153,8 @@ already specified in the QtCore typesystem (see :ref:`primitive-cpp-types`).
             until="..."
             target-lang-api-name="..."
             default-constructor="..."
-            preferred-conversion="yes | no" />
-            view-on="..."
+            preferred-conversion="yes | no"
+            view-on="..." />
     </typesystem>
 
 The **name** attribute is the name of the primitive in C++.
@@ -266,6 +280,7 @@ and it is a child of the :ref:`typesystem` node. Use
             flags="yes | no"
             flags-revision="..."
             cpp-type = "..."
+            doc-file = "..."
             python-type = "IntEnum | IntFlag"
             lower-bound="..."
             upper-bound="..."
@@ -300,6 +315,11 @@ The *optional* **cpp-type** attribute specifies a C++ to be used for
 casting values. This can be useful for large values triggering MSVC
 signedness issues.
 
+The *optional* **doc-file** attribute specifies the base name of the C++ or
+``.qdoc`` file indicated by ``\relates`` or ``\headerfile`` in ``qdoc``, to
+which the documentation of the enumeration is to be added and displayed in the
+case its a global enumeration. This attribute is for ``qdoc`` only.
+
 The **revision** attribute can be used to specify a revision for each type, easing the
 production of ABI compatible bindings.
 
@@ -433,7 +453,9 @@ or other type nodes and may contain :ref:`add-function`, :ref:`add-pymethoddef`,
          parent-management="yes | no"
          polymorphic-id-expression="..."
          polymorphic-name-function="..."
+         polymorphic-base="yes | no"
          private="yes | no"
+         qt-metaobject="yes | no"
          qt-register-metatype = "yes | no | base"
          stream="yes | no"
          revision="..."
@@ -461,6 +483,12 @@ parameter, or similar).
 
 For the *optional* **private** attribute, see :ref:`private_types`.
 
+The *optional* **qt-metaobject** attribute specifies whether
+the special Qt virtual functions ``metaObject()``,
+``metaCall()``, and ``metaCast()`` are generated. For classes
+using dynamic meta objects, for example, ``QDBusInterface``,
+it can be turned off.
+
 The *optional* **qt-register-metatype** attribute determines whether
 a Qt meta type registration is generated for ``name *``. By
 default, this is only generated for non-QObject types for usage
@@ -508,18 +536,8 @@ type system has this attribute set, the heuristics will be applied
 to all classes. In shiboken 7, it will be mandatory to set the
 attribute.
 
-The *optional* **polymorphic-id-expression** attribute specifies an
-expression checking whether a base class pointer is of the matching
-type. For example, in a ``virtual eventHandler(BaseEvent *e)``
-function, this is used to construct a Python wrapper matching
-the derived class (for example, a ``MouseEvent`` or similar).
-
-The *optional* **polymorphic-name-function** specifies the name of a
-function returning the type name of a derived class on the base class
-type entry. Normally, ``typeid(ptr).name()`` is used for this.
-However, this fails if the type hierarchy does not have virtual functions.
-In this case, a function is required which typically decides depending
-on some type enumeration.
+For the *optional* **polymorphic-id-expression**, **polymorphic-name-function**
+and **polymorphic-base** attributes, see :ref:`typediscovery-attributes`.
 
 interface-type
 ^^^^^^^^^^^^^^
@@ -772,6 +790,7 @@ and may contain a :ref:`modify-function` child node.
     <typesystem>
         <function signature="..." rename="..." since="..."
                   allow-thread="true | auto | false"
+                  doc-file = "..."
                   exception-handling="off | auto-off | auto-on | on"
                   overload-number="number"
                   snake-case="yes | no | both" />
@@ -785,6 +804,11 @@ the function was introduced.
 
 The *optional* **rename** attribute is used to modify the function name.
 
+The *optional* **doc-file** attribute specifies the base name of the C++ or
+``.qdoc`` file indicated by ``\relates`` or ``\headerfile`` in ``qdoc``, to
+which the documentation of the function is to be added and displayed in the
+case its a global function. This attribute is for ``qdoc`` only.
+
 For the *optional* attributes **allow-thread**, **exception-handling**,
 **overload-number** and **snake-case**, see :ref:`modify-function`.
 
index 7785b8f9120126b1031d35a6e6cfdfc0bf56637f..a0132653018ad09dd381680bfbd1011728eb503f 100644 (file)
@@ -30,8 +30,8 @@
 
 using namespace Qt::StringLiterals;
 
-static const char ENABLE_PYSIDE_EXTENSIONS[] = "enable-pyside-extensions";
-static const char AVOID_PROTECTED_HACK[] = "avoid-protected-hack";
+static constexpr auto ENABLE_PYSIDE_EXTENSIONS = "enable-pyside-extensions"_L1;
+static constexpr auto AVOID_PROTECTED_HACK = "avoid-protected-hack"_L1;
 
 struct GeneratorOptions
 {
@@ -52,6 +52,9 @@ struct Generator::GeneratorPrivate
 
 GeneratorOptions Generator::GeneratorPrivate::m_options;
 
+// Kept as a variable for a potential Qt-in-namespace support
+QString Generator::m_gsp = "::"_L1;
+
 Generator::Generator() : m_d(new GeneratorPrivate)
 {
 }
@@ -89,9 +92,9 @@ bool Generator::setup(const ApiExtractorResult &api)
 QList<OptionDescription> Generator::options()
 {
     return {
-        {QLatin1StringView(AVOID_PROTECTED_HACK),
+        {AVOID_PROTECTED_HACK,
          u"Avoid the use of the '#define protected public' hack."_s},
-        {QLatin1StringView(ENABLE_PYSIDE_EXTENSIONS),
+        {ENABLE_PYSIDE_EXTENSIONS,
          u"Enable PySide extensions, such as support for signal/slots,\n"
           "use this if you are creating a binding for a Qt-based library."_s}
     };
@@ -112,9 +115,9 @@ bool GeneratorOptionsParser::handleBoolOption(const QString & key, OptionSource
 {
     if (source == OptionSource::CommandLineSingleDash)
         return false;
-    if (key == QLatin1StringView(ENABLE_PYSIDE_EXTENSIONS))
+    if (key == ENABLE_PYSIDE_EXTENSIONS)
         return ( m_options->usePySideExtensions = true);
-    if (key == QLatin1StringView(AVOID_PROTECTED_HACK))
+    if (key == AVOID_PROTECTED_HACK)
         return ( m_options->avoidProtectedHack = true);
     return false;
 }
@@ -228,10 +231,9 @@ QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType &smartP
     const AbstractMetaType innerType = smartPointerType.getSmartPointerInnerType();
     smartPointerType.typeEntry()->qualifiedCppName();
     QString fileName = smartPointerType.typeEntry()->qualifiedCppName().toLower();
-    fileName.replace(u"::"_s, u"_"_s);
-    fileName.append(u"_"_s);
+    fileName.append(u'_');
     fileName.append(innerType.name().toLower());
-
+    fileName.replace(u"::"_s, u"_"_s); // std::shared_ptr<std::string>
     return fileName;
 }
 
@@ -308,9 +310,7 @@ QString Generator::getFullTypeName(TypeEntryCPtr type)
     QString result = type->qualifiedCppName();
     if (type->isArray())
         type = std::static_pointer_cast<const ArrayTypeEntry>(type)->nestedTypeEntry();
-    if (!isCppPrimitive(type))
-        result.prepend(u"::"_s);
-    return result;
+    return isCppPrimitive(type) ? result : addGlobalScopePrefix(result);
 }
 
 QString Generator::getFullTypeName(const AbstractMetaType &type)
@@ -320,7 +320,7 @@ QString Generator::getFullTypeName(const AbstractMetaType &type)
     if (type.isVoidPointer())
         return u"void*"_s;
     if (type.typeEntry()->isContainer())
-        return u"::"_s + type.cppSignature();
+        return addGlobalScopePrefix(type.cppSignature());
     QString typeName;
     if (type.typeEntry()->isComplex() && type.hasInstantiations())
         typeName = getFullTypeNameWithoutModifiers(type);
@@ -331,7 +331,9 @@ QString Generator::getFullTypeName(const AbstractMetaType &type)
 
 QString Generator::getFullTypeName(const AbstractMetaClassCPtr &metaClass)
 {
-    return u"::"_s + metaClass->qualifiedCppName();
+    const QString &qualName = metaClass->qualifiedCppName();
+    // Typedefs are generated into the global namespace
+    return metaClass->isTypeDef() ? qualName : addGlobalScopePrefix(qualName);
 }
 
 QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType &type)
@@ -357,7 +359,7 @@ QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType &type)
     }
     while (typeName.endsWith(u'*') || typeName.endsWith(u' '))
         typeName.chop(1);
-    return u"::"_s + typeName;
+    return addGlobalScopePrefix(typeName);
 }
 
 std::optional<DefaultValue>
@@ -645,6 +647,16 @@ QString Generator::subDirectoryForPackage(QString packageNameIn) const
     return packageNameIn;
 }
 
+QString Generator::addGlobalScopePrefix(const QString &t)
+{
+    return t.startsWith("std::"_L1) ? t : m_gsp + t;
+}
+
+QString Generator::globalScopePrefix(const GeneratorContext &classContext)
+{
+    return classContext.useWrapper() ? QString{} : m_gsp;
+}
+
 template<typename T>
 static QString getClassTargetFullName_(T t, bool includePackageName)
 {
index 2b8784a362d06c7763c537dd11c700d0ccf029da..5b051b599dcac74eb7a0909064b900a943e8e927 100644 (file)
@@ -214,6 +214,11 @@ protected:
     */
     virtual QString subDirectoryForPackage(QString packageName = QString()) const;
 
+    static QString addGlobalScopePrefix(const QString &t);
+    static QString globalScopePrefix(const GeneratorContext &classContext);
+
+    static QString m_gsp;
+
 private:
     struct GeneratorPrivate;
     GeneratorPrivate *m_d;
index bba60fa9a6011f53ebac796a68392506763a06cd..9fb5b9bf61a5f1ab2cd41e27c9f0df9f26a57de7 100644 (file)
 
 using namespace Qt::StringLiterals;
 
+static inline QString classScope(const AbstractMetaClassCPtr &metaClass)
+{
+    return metaClass->fullName();
+}
+
+struct DocPackage
+{
+    QStringList classPages;
+    QStringList decoratorPages;
+    AbstractMetaFunctionCList globalFunctions;
+    AbstractMetaEnumList globalEnums;
+};
+
 struct DocGeneratorOptions
 {
     QtXmlToSphinxParameters parameters;
@@ -69,8 +82,7 @@ struct GeneratorDocumentation
         AbstractMetaFunctionCPtr notify;
     };
 
-    AbstractMetaFunctionCList constructors;
-    AbstractMetaFunctionCList allFunctions; // Except constructors
+    AbstractMetaFunctionCList allFunctions;
     AbstractMetaFunctionCList tocNormalFunctions; // Index lists
     AbstractMetaFunctionCList tocVirtuals;
     AbstractMetaFunctionCList tocSignalFunctions;
@@ -86,19 +98,18 @@ static bool operator<(const GeneratorDocumentation::Property &lhs,
     return lhs.name < rhs.name;
 }
 
-static QString propertyRefTarget(const AbstractMetaClassCPtr &cppClass, const QString &name)
+static QString propertyRefTarget(const QString &name)
 {
-    QString result = cppClass->fullName() +  u'.' + name;
-    result.replace(u"::"_s, u"."_s);
+    QString result = name;
     // For sphinx referencing, disambiguate the target from the getter name
-    // by inserting an invisible "Hangul choseong filler" character.
-    result.insert(1, QChar(0x115F));
+    // by appending an invisible "Hangul choseong filler" character.
+    result.append(QChar(0x115F));
     return result;
 }
 
-static inline QString additionalDocumentationOption() { return QStringLiteral("additional-documentation"); }
+constexpr auto additionalDocumentationOption = "additional-documentation"_L1;
 
-static inline QString none() { return QStringLiteral("None"); }
+constexpr auto none = "None"_L1;
 
 static bool shouldSkip(const AbstractMetaFunctionCPtr &func)
 {
@@ -135,7 +146,14 @@ static bool shouldSkip(const AbstractMetaFunctionCPtr &func)
 
 static bool functionSort(const AbstractMetaFunctionCPtr &func1, const AbstractMetaFunctionCPtr &func2)
 {
-    return func1->name() < func2->name();
+    const bool ctor1 = func1->isConstructor();
+    if (ctor1 != func2->isConstructor())
+        return ctor1;
+    const QString &name1 = func1->name();
+    const QString &name2 = func2->name();
+    if (name1 != name2)
+        return name1 < name2;
+    return func1->arguments().size() < func2->arguments().size();
 }
 
 static inline QVersionNumber versionOf(const TypeEntryCPtr &te)
@@ -148,77 +166,136 @@ static inline QVersionNumber versionOf(const TypeEntryCPtr &te)
     return {};
 }
 
-// Format a documentation reference (meth/attr): ":meth:`name<target>`"
-// We do not use the short form ":meth:`~target`" since that adds parentheses ()
-// for functions where we list the parameters instead.
 struct docRef
 {
-    explicit docRef(const char *kind, const QString &name,
-                    const AbstractMetaClassCPtr &cppClass) :
-        m_kind(kind), m_name(name), m_cppClass(cppClass) {}
+    explicit docRef(const char *kind, QAnyStringView name) :
+        m_kind(kind), m_name(name) {}
 
     const char *m_kind;
-    const QString &m_name;
-    const AbstractMetaClassCPtr m_cppClass;
+    QAnyStringView m_name;
 };
 
 static TextStream &operator<<(TextStream &s, const docRef &dr)
 {
-    QString className = dr.m_cppClass->fullName();
-    className.replace(u"::"_s, u"."_s);
-    s << ':' << dr.m_kind << ":`" << dr.m_name << '<';
-    if (!dr.m_name.startsWith(className))
-        s << className << '.';
-    s << dr.m_name << ">`";
+    s << ':' << dr.m_kind << ":`" << dr.m_name << '`';
     return s;
 }
 
+static QString fileNameToTocEntry(const QString &fileName)
+{
+    constexpr auto rstSuffix = ".rst"_L1;
+
+    QString result = fileName;
+    if (result.endsWith(rstSuffix))
+        result.chop(rstSuffix.size()); // Remove the .rst extension
+    // skip namespace if necessary
+    auto lastDot = result.lastIndexOf(u'.');
+    if (lastDot != -1)
+        result.remove(0, lastDot + 1);
+    return result;
+}
+
+static void readExtraDoc(const QFileInfo &fi,
+                         const QString &moduleName,
+                         const QString &outputDir,
+                         DocPackage *docPackage, QStringList *extraTocEntries)
+{
+    // Strip to "Property.rst" in output directory
+    const QString newFileName = fi.fileName().mid(moduleName.size() + 1);
+    QFile sourceFile(fi.absoluteFilePath());
+    if (!sourceFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
+        qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotOpenForReading(sourceFile)));
+        return;
+    }
+    const QByteArray contents = sourceFile.readAll();
+    sourceFile.close();
+    QFile targetFile(outputDir + u'/' + newFileName);
+    if (!targetFile.open(QIODevice::WriteOnly|QIODevice::Text)) {
+        qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotOpenForWriting(targetFile)));
+        return;
+    }
+    targetFile.write(contents);
+    if (contents.contains("decorator::"))
+        docPackage->decoratorPages.append(newFileName);
+    else
+        docPackage->classPages.append(newFileName);
+    extraTocEntries->append(fileNameToTocEntry(newFileName));
+}
+
 // Format a short documentation reference (automatically dropping the prefix
 // by using '~'), usable for property/attributes ("attr").
 struct shortDocRef
 {
-    explicit shortDocRef(const char *kind, const QString &target) :
-        m_kind(kind), m_target(target) {}
+    explicit shortDocRef(const char *kind, QAnyStringView name) :
+        m_kind(kind), m_name(name) {}
 
     const char *m_kind;
-    const QString &m_target;
+    QAnyStringView m_name;
 };
 
 static TextStream &operator<<(TextStream &s, const shortDocRef &sdr)
 {
-    s << ':' << sdr.m_kind << ":`~" << sdr.m_target << '`';
+    s << ':' << sdr.m_kind << ":`~" << sdr.m_name << '`';
     return s;
 }
 
 struct functionRef : public docRef
 {
-    explicit functionRef(const QString &name, const AbstractMetaClassCPtr &cppClass) :
-        docRef("meth", name, cppClass) {}
+    explicit functionRef(QAnyStringView name) : docRef("meth", name) {}
+};
+
+struct classRef : public shortDocRef
+{
+    explicit classRef(QAnyStringView name) : shortDocRef("class", name) {}
+};
+
+struct propRef : public shortDocRef // Attribute/property (short) reference
+{
+    explicit propRef(const QString &target) :
+        shortDocRef("attr", target) {}
 };
 
-struct functionTocEntry // Format a TOC entry for a function
+struct headline
 {
-    explicit functionTocEntry(const AbstractMetaFunctionCPtr& func,
-                              const AbstractMetaClassCPtr &cppClass) :
-        m_func(func), m_cppClass(cppClass) {}
+    explicit headline(QAnyStringView title, char underLineChar = '-') :
+        m_title(title), m_underLineChar(underLineChar) {}
 
-    AbstractMetaFunctionCPtr m_func;
-    const AbstractMetaClassCPtr m_cppClass;
+    QAnyStringView m_title;
+    char m_underLineChar;
 };
 
-static TextStream &operator<<(TextStream &s, const functionTocEntry &ft)
+static TextStream &operator<<(TextStream &s, const headline &h)
 {
-    s << functionRef(QtDocGenerator::getFuncName(ft.m_func), ft.m_cppClass)
-        << ' ' << QtDocGenerator::formatArgs(ft.m_func);
+    s << h.m_title << '\n' << Pad(h.m_underLineChar, h.m_title.size()) << "\n\n";
     return s;
 }
 
-struct propRef : public shortDocRef // Attribute/property (short) reference
+struct pyClass
 {
-    explicit propRef(const QString &target) :
-        shortDocRef("attr", target) {}
+    explicit pyClass(QAnyStringView name) : m_name(name)  {}
+
+    QAnyStringView m_name;
+};
+
+static TextStream &operator<<(TextStream &s, pyClass c)
+{
+    s << ".. py:class:: " << c.m_name << "\n\n";
+    return s;
+}
+
+struct currentModule
+{
+    explicit currentModule(QAnyStringView module) : m_module(module)  {}
+
+    QAnyStringView m_module;
 };
 
+static TextStream &operator<<(TextStream &s, const currentModule &m)
+{
+    s << ".. currentmodule:: " << m.m_module << "\n\n\n";
+    return s;
+}
+
 DocGeneratorOptions QtDocGenerator::m_options;
 
 QtDocGenerator::QtDocGenerator()
@@ -248,28 +325,23 @@ QString QtDocGenerator::fileNameForContext(const GeneratorContext &context) cons
 }
 
 void QtDocGenerator::writeFormattedBriefText(TextStream &s, const Documentation &doc,
-                                             const AbstractMetaClassCPtr &metaclass) const
+                                             const QString &scope) const
 {
-    writeFormattedText(s, doc.brief(), doc.format(), metaclass);
+    writeFormattedText(s, doc.brief(), doc.format(), scope);
 }
 
 void QtDocGenerator::writeFormattedDetailedText(TextStream &s, const Documentation &doc,
-                                                const AbstractMetaClassCPtr &metaclass) const
+                                                const QString &scope) const
 {
-    writeFormattedText(s, doc.detailed(), doc.format(), metaclass);
+    writeFormattedText(s, doc.detailed(), doc.format(), scope);
 }
 
 void QtDocGenerator::writeFormattedText(TextStream &s, const QString &doc,
                                         Documentation::Format format,
-                                        const AbstractMetaClassCPtr &metaClass) const
+                                        const QString &scope) const
 {
-    QString metaClassName;
-
-    if (metaClass)
-        metaClassName = metaClass->fullName();
-
     if (format == Documentation::Native) {
-        QtXmlToSphinx x(this, m_options.parameters, doc, metaClassName);
+        QtXmlToSphinx x(this, m_options.parameters, doc, scope);
         s << x;
     } else {
         const auto lines = QStringView{doc}.split(u'\n');
@@ -300,7 +372,7 @@ static void writeInheritanceList(TextStream &s, const AbstractMetaClassCList& cl
     for (qsizetype i = 0, size = classes.size(); i < size; ++i) {
         if (i > 0)
             s << ", ";
-        s << ":ref:`" << classes.at(i)->name() << '`';
+        s << classRef(classes.at(i)->fullName());
     }
     s << "\n\n";
 }
@@ -337,21 +409,18 @@ void QtDocGenerator::generateClass(TextStream &s, const GeneratorContext &classC
     AbstractMetaClassCPtr metaClass = classContext.metaClass();
     qCDebug(lcShibokenDoc).noquote().nospace() << "Generating Documentation for " << metaClass->fullName();
 
-    m_packages[metaClass->package()] << fileNameForContext(classContext);
+    m_packages[metaClass->package()].classPages << fileNameForContext(classContext);
 
     m_docParser->setPackageName(metaClass->package());
     m_docParser->fillDocumentation(std::const_pointer_cast<AbstractMetaClass>(metaClass));
 
-    QString className = metaClass->name();
-    s << ".. _" << className << ":" << "\n\n";
-    s << ".. currentmodule:: " << metaClass->package() << "\n\n\n";
-
-    s << className << '\n';
-    s << Pad('*', className.size()) << "\n\n";
+    s << currentModule(metaClass->package()) << pyClass(metaClass->name());
+    Indentation indent(s);
 
     auto documentation = metaClass->documentation();
+    const QString scope = classScope(metaClass);
     if (documentation.hasBrief())
-        writeFormattedBriefText(s, documentation, metaClass);
+        writeFormattedBriefText(s, documentation, scope);
 
     if (!metaClass->baseClasses().isEmpty()) {
         if (m_options.inheritanceDiagram) {
@@ -373,13 +442,13 @@ void QtDocGenerator::generateClass(TextStream &s, const GeneratorContext &classC
     const GeneratorDocumentation doc = generatorDocumentation(metaClass);
 
     if (!doc.allFunctions.isEmpty() || !doc.properties.isEmpty()) {
-        s << "\nSynopsis\n--------\n\n";
-        writePropertyToc(s, doc, metaClass);
-        writeFunctionToc(s, u"Functions"_s, metaClass, doc.tocNormalFunctions);
-        writeFunctionToc(s, u"Virtual functions"_s, metaClass, doc.tocVirtuals);
-        writeFunctionToc(s, u"Slots"_s, metaClass, doc.tocSlotFunctions);
-        writeFunctionToc(s, u"Signals"_s, metaClass, doc.tocSignalFunctions);
-        writeFunctionToc(s, u"Static functions"_s, metaClass, doc.tocStaticFunctions);
+        s << '\n' << headline("Synopsis");
+        writePropertyToc(s, doc);
+        writeFunctionToc(s, u"Methods"_s, doc.tocNormalFunctions);
+        writeFunctionToc(s, u"Virtual methods"_s, doc.tocVirtuals);
+        writeFunctionToc(s, u"Slots"_s, doc.tocSlotFunctions);
+        writeFunctionToc(s, u"Signals"_s, doc.tocSignalFunctions);
+        writeFunctionToc(s, u"Static functions"_s, doc.tocStaticFunctions);
     }
 
     s << "\n.. note::\n"
@@ -389,64 +458,52 @@ void QtDocGenerator::generateClass(TextStream &s, const GeneratorContext &classC
          "    translation, you can also let us know by creating a ticket on\n"
          "    https:/bugreports.qt.io/projects/PYSIDE\n\n";
 
-    s << "\nDetailed Description\n"
-           "--------------------\n\n"
-        << ".. _More:\n";
+    s << '\n' << headline("Detailed Description") << ".. _More:\n";
 
-    writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass, nullptr);
-    if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass, nullptr))
-        writeFormattedDetailedText(s, documentation, metaClass);
+    writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass);
+    if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass))
+        writeFormattedDetailedText(s, documentation, scope);
+    writeInjectDocumentation(s, TypeSystem::DocModificationAppend, metaClass);
 
-    if (!metaClass->isNamespace())
-        writeConstructors(s, metaClass, doc.constructors);
+    writeEnums(s, metaClass->enums(), scope);
 
     if (!doc.properties.isEmpty())
         writeProperties(s, doc, metaClass);
 
-    writeEnums(s, metaClass);
     if (!metaClass->isNamespace())
         writeFields(s, metaClass);
 
-    QString lastName;
-    for (const auto &func : std::as_const(doc.allFunctions)) {
-        const bool indexed = func->name() != lastName;
-        lastName = func->name();
-        s << (func->isStatic() ? ".. py:staticmethod:: " : ".. py:method:: ");
-        writeFunction(s, metaClass, func, indexed);
-    }
-
-    writeInjectDocumentation(s, TypeSystem::DocModificationAppend, metaClass, nullptr);
+    writeFunctions(s, doc.allFunctions, metaClass, scope);
 }
 
 void QtDocGenerator::writeFunctionToc(TextStream &s, const QString &title,
-                                      const AbstractMetaClassCPtr &cppClass,
                                       const AbstractMetaFunctionCList &functions)
 {
     if (!functions.isEmpty()) {
-        s << title << '\n'
-          << Pad('^', title.size()) << '\n';
-
-        s << ".. container:: function_list\n\n" << indent;
-        for (const auto &func : functions)
-            s << "* def " << functionTocEntry(func, cppClass) << '\n';
+        s << headline(title, '^')
+          << ".. container:: function_list\n\n" << indent;
+        // Functions are sorted by the Metabuilder; erase overloads
+        QStringList toc;
+        toc.reserve(functions.size());
+        std::transform(functions.cbegin(), functions.end(),
+                       std::back_inserter(toc), getFuncName);
+        toc.erase(std::unique(toc.begin(), toc.end()), toc.end());
+        for (const auto &func : toc)
+            s << "* def " << functionRef(func) << '\n';
         s << outdent << "\n\n";
     }
 }
 
 void QtDocGenerator::writePropertyToc(TextStream &s,
-                                      const GeneratorDocumentation &doc,
-                                      const AbstractMetaClassCPtr &cppClass)
+                                      const GeneratorDocumentation &doc)
 {
     if (doc.properties.isEmpty())
         return;
 
-    const QString title = u"Properties"_s;
-    s << title << '\n'
-      << Pad('^', title.size()) << '\n';
-
-    s << ".. container:: function_list\n\n" << indent;
+    s << headline("Properties", '^')
+        << ".. container:: function_list\n\n" << indent;
     for (const auto &prop : doc.properties) {
-        s << "* " << propRef(propertyRefTarget(cppClass, prop.name));
+        s << "* " << propRef(propertyRefTarget(prop.name));
         if (prop.documentation.hasBrief())
             s << " - " << prop.documentation.brief();
         s << '\n';
@@ -462,32 +519,33 @@ void QtDocGenerator::writeProperties(TextStream &s,
         << "``from __feature__ import true_property`` is used or via accessor "
         << "functions otherwise.\n\n";
 
+    const QString scope = classScope(cppClass);
     for (const auto &prop : doc.properties) {
         const QString type = translateToPythonType(prop.type, cppClass, /* createRef */ false);
-        s <<  ".. py:property:: " << propertyRefTarget(cppClass, prop.name)
+        s <<  ".. py:property:: " << propertyRefTarget(prop.name)
             << "\n   :type: " << type << "\n\n\n";
         if (!prop.documentation.isEmpty())
-            writeFormattedText(s, prop.documentation.detailed(), Documentation::Native, cppClass);
+            writeFormattedText(s, prop.documentation.detailed(), Documentation::Native, scope);
         s << "**Access functions:**\n";
         if (prop.getter)
-            s << " * " << functionTocEntry(prop.getter, cppClass) << '\n';
+            s << " * " << functionRef(prop.getter->name()) << '\n';
         if (prop.setter)
-            s << " * " << functionTocEntry(prop.setter, cppClass) << '\n';
+            s << " * " << functionRef(prop.setter->name()) << '\n';
         if (prop.reset)
-            s << " * " << functionTocEntry(prop.reset, cppClass) << '\n';
+            s << " * " << functionRef(prop.reset->name()) << '\n';
         if (prop.notify)
-            s << " * Signal " << functionTocEntry(prop.notify, cppClass) << '\n';
+            s << " * Signal " << functionRef(prop.notify->name()) << '\n';
         s << '\n';
     }
 }
 
-void QtDocGenerator::writeEnums(TextStream &s, const AbstractMetaClassCPtr &cppClass) const
+void QtDocGenerator::writeEnums(TextStream &s, const AbstractMetaEnumList &enums,
+                                const QString &scope) const
 {
-    static const QString section_title = u".. attribute:: "_s;
-
-    for (const AbstractMetaEnum &en : cppClass->enums()) {
-        s << section_title << cppClass->fullName() << '.' << en.name() << "\n\n";
-        writeFormattedDetailedText(s, en.documentation(), cppClass);
+    for (const AbstractMetaEnum &en : enums) {
+        s << pyClass(en.name());
+        Indentation indent(s);
+        writeFormattedDetailedText(s, en.documentation(), scope);
         const auto version = versionOf(en.typeEntry());
         if (!version.isNull())
             s << rstVersionAdded(version);
@@ -497,64 +555,15 @@ void QtDocGenerator::writeEnums(TextStream &s, const AbstractMetaClassCPtr &cppC
 
 void QtDocGenerator::writeFields(TextStream &s, const AbstractMetaClassCPtr &cppClass) const
 {
-    static const QString section_title = u".. attribute:: "_s;
+    constexpr auto section_title = ".. attribute:: "_L1;
 
+    const QString scope = classScope(cppClass);
     for (const AbstractMetaField &field : cppClass->fields()) {
         s << section_title << cppClass->fullName() << "." << field.name() << "\n\n";
-        writeFormattedDetailedText(s, field.documentation(), cppClass);
+        writeFormattedDetailedText(s, field.documentation(), scope);
     }
 }
 
-void QtDocGenerator::writeConstructors(TextStream &s, const AbstractMetaClassCPtr &cppClass,
-                                       const AbstractMetaFunctionCList &constructors) const
-{
-    static const QString sectionTitle = u".. class:: "_s;
-
-    bool first = true;
-    QHash<QString, AbstractMetaArgument> arg_map;
-
-    if (constructors.isEmpty()) {
-        s << sectionTitle << cppClass->fullName();
-    } else {
-        QByteArray pad;
-        for (const auto &func : constructors) {
-            s << pad;
-            if (first) {
-                first = false;
-                s << sectionTitle;
-                pad = QByteArray(sectionTitle.size(), ' ');
-            }
-            s << functionSignature(cppClass, func) << "\n\n";
-
-            const auto version = versionOf(func->typeEntry());
-            if (!version.isNull())
-                s << pad << rstVersionAdded(version);
-            if (func->isDeprecated())
-                s << pad << rstDeprecationNote("constructor");
-
-            const AbstractMetaArgumentList &arguments = func->arguments();
-            for (const AbstractMetaArgument &arg : arguments) {
-                if (!arg_map.contains(arg.name())) {
-                    arg_map.insert(arg.name(), arg);
-                }
-            }
-        }
-    }
-
-    s << '\n';
-
-    for (auto it = arg_map.cbegin(), end = arg_map.cend(); it != end; ++it) {
-        s.indent(2);
-        writeParameterType(s, cppClass, it.value());
-        s.outdent(2);
-    }
-
-    s << '\n';
-
-    for (const auto &func : constructors)
-        writeFormattedDetailedText(s, func->documentation(), cppClass);
-}
-
 QString QtDocGenerator::formatArgs(const AbstractMetaFunctionCPtr &func)
 {
     QString ret = u"("_s;
@@ -586,13 +595,13 @@ QString QtDocGenerator::formatArgs(const AbstractMetaFunctionCPtr &func)
                        || defValue.startsWith(u"QList")) {
                 defValue = u"list()"_s;
             } else if (defValue == u"QVariant()") {
-                defValue = none();
+                defValue = none;
             } else {
                 defValue.replace(u"::"_s, u"."_s);
                 if (defValue == u"nullptr")
-                    defValue = none();
+                    defValue = none;
                 else if (defValue == u"0" && arg.type().isObject())
-                    defValue = none();
+                    defValue = none;
             }
             ret += u'=' + defValue;
         }
@@ -660,25 +669,21 @@ void QtDocGenerator::writeDocSnips(TextStream &s,
     }
 }
 
-bool QtDocGenerator::writeInjectDocumentation(TextStream &s,
-                                            TypeSystem::DocModificationMode mode,
-                                            const AbstractMetaClassCPtr &cppClass,
-                                            const AbstractMetaFunctionCPtr &func)
+bool QtDocGenerator::writeDocModifications(TextStream &s,
+                                           const DocModificationList &mods,
+                                           TypeSystem::DocModificationMode mode,
+                                           const QString &scope) const
 {
-    Indentation indentation(s);
     bool didSomething = false;
-
-    const DocModificationList mods = DocParser::getDocModifications(cppClass, func);
-
     for (const DocModification &mod : mods) {
         if (mod.mode() == mode) {
             switch (mod.format()) {
             case TypeSystem::NativeCode:
-                writeFormattedText(s, mod.code(), Documentation::Native, cppClass);
+                writeFormattedText(s, mod.code(), Documentation::Native, scope);
                 didSomething = true;
                 break;
             case TypeSystem::TargetLangCode:
-                writeFormattedText(s, mod.code(), Documentation::Target, cppClass);
+                writeFormattedText(s, mod.code(), Documentation::Target, scope);
                 didSomething = true;
                 break;
             default:
@@ -686,33 +691,46 @@ bool QtDocGenerator::writeInjectDocumentation(TextStream &s,
             }
         }
     }
+    return didSomething;
+}
 
+bool QtDocGenerator::writeInjectDocumentation(TextStream &s,
+                                              TypeSystem::DocModificationMode mode,
+                                              const AbstractMetaClassCPtr &cppClass) const
+{
+    const bool didSomething =
+        writeDocModifications(s, DocParser::getDocModifications(cppClass),
+                              mode, classScope(cppClass));
     s << '\n';
 
     // FIXME PYSIDE-7: Deprecate the use of doc string on glue code.
     //       This is pre "add-function" and "inject-documentation" tags.
     const TypeSystem::CodeSnipPosition pos = mode == TypeSystem::DocModificationPrepend
         ? TypeSystem::CodeSnipPositionBeginning : TypeSystem::CodeSnipPositionEnd;
-    if (func)
-        writeDocSnips(s, func->injectedCodeSnips(), pos, TypeSystem::TargetLangCode);
-    else
-        writeDocSnips(s, cppClass->typeEntry()->codeSnips(), pos, TypeSystem::TargetLangCode);
+    writeDocSnips(s, cppClass->typeEntry()->codeSnips(), pos, TypeSystem::TargetLangCode);
     return didSomething;
 }
 
-QString QtDocGenerator::functionSignature(const AbstractMetaClassCPtr &cppClass,
-                                          const AbstractMetaFunctionCPtr &func)
+bool QtDocGenerator::writeInjectDocumentation(TextStream &s,
+                                              TypeSystem::DocModificationMode mode,
+                                              const DocModificationList &modifications,
+                                              const AbstractMetaFunctionCPtr &func,
+                                              const QString &scope) const
 {
-    QString funcName = cppClass->fullName();
-    if (!func->isConstructor())
-        funcName += u'.' + getFuncName(func);
+    const bool didSomething = writeDocModifications(s, modifications, mode, scope);
+    s << '\n';
 
-    return funcName + formatArgs(func);
+    // FIXME PYSIDE-7: Deprecate the use of doc string on glue code.
+    //       This is pre "add-function" and "inject-documentation" tags.
+    const TypeSystem::CodeSnipPosition pos = mode == TypeSystem::DocModificationPrepend
+        ? TypeSystem::CodeSnipPositionBeginning : TypeSystem::CodeSnipPositionEnd;
+    writeDocSnips(s, func->injectedCodeSnips(), pos, TypeSystem::TargetLangCode);
+    return didSomething;
 }
 
 static QString inline toRef(const QString &t)
 {
-    return ":any:`"_L1 + t + u'`';
+    return ":class:`~"_L1 + t + u'`';
 }
 
 QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type,
@@ -720,7 +738,7 @@ QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type,
                                               bool createRef) const
 {
     static const QStringList nativeTypes =
-        {boolT(), floatT(), intT(), pyObjectT(), pyStrT()};
+        {boolT, floatT, intT, pyObjectT, pyStrT};
 
     QString name = type.name();
     if (nativeTypes.contains(name))
@@ -730,24 +748,24 @@ QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type,
         const auto &basicName = basicReferencedTypeEntry(type.typeEntry())->name();
         if (AbstractMetaType::cppSignedIntTypes().contains(basicName)
             || AbstractMetaType::cppUnsignedIntTypes().contains(basicName)) {
-            return intT();
+            return intT;
         }
         if (AbstractMetaType::cppFloatTypes().contains(basicName))
-            return floatT();
+            return floatT;
     }
 
     static const QSet<QString> stringTypes = {
         u"uchar"_s, u"std::string"_s, u"std::wstring"_s,
         u"std::stringview"_s, u"std::wstringview"_s,
-        qStringT(), u"QStringView"_s, u"QAnyStringView"_s, u"QUtf8StringView"_s
+        qStringT, u"QStringView"_s, u"QAnyStringView"_s, u"QUtf8StringView"_s
     };
     if (stringTypes.contains(name))
-        return pyStrT();
+        return pyStrT;
 
     static const QHash<QString, QString> typeMap = {
-        { cPyObjectT(), pyObjectT() },
+        { cPyObjectT, pyObjectT },
         { u"QStringList"_s, u"list of strings"_s },
-        { qVariantT(), pyObjectT() }
+        { qVariantT, pyObjectT }
     };
     const auto found = typeMap.constFind(name);
     if (found != typeMap.cend())
@@ -755,8 +773,17 @@ QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type,
 
     if (type.isFlags()) {
         const auto fte = std::static_pointer_cast<const FlagsTypeEntry>(type.typeEntry());
-        auto enumName = fte->originator()->targetLangName();
+        auto enumTypeEntry = fte->originator();
+        auto enumName = enumTypeEntry->targetLangName();
+        if (createRef)
+            enumName.prepend(enumTypeEntry->targetLangPackage() + u'.');
         return "Combination of "_L1 + (createRef ? toRef(enumName) : enumName);
+    } else if (type.isEnum()) {
+        auto enumTypeEntry = std::static_pointer_cast<const EnumTypeEntry>(type.typeEntry());
+        auto enumName = enumTypeEntry->targetLangName();
+        if (createRef)
+            enumName.prepend(enumTypeEntry->targetLangPackage() + u'.');
+        return createRef ? toRef(enumName) : enumName;
     }
 
     if (type.isConstant() && name == "char"_L1 && type.indirections() == 1)
@@ -782,13 +809,15 @@ QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type,
     }
 
     if (auto k = AbstractMetaClass::findClass(api().classes(), type.typeEntry()))
-        return createRef ? toRef(k->fullName()) : k->fullName();
+        return createRef ? toRef(k->fullName()) : k->name();
 
     return createRef ? toRef(name) : name;
 }
 
 QString QtDocGenerator::getFuncName(const AbstractMetaFunctionCPtr &cppFunc)
 {
+    if (cppFunc->isConstructor())
+        return "__init__"_L1;
     QString result = cppFunc->name();
     if (cppFunc->isOperatorOverload()) {
         const QString pythonOperator = Generator::pythonOperatorFunctionName(result);
@@ -832,16 +861,40 @@ void QtDocGenerator::writeFunctionParametersType(TextStream &s,
     s << '\n';
 }
 
-void QtDocGenerator::writeFunction(TextStream &s, const AbstractMetaClassCPtr &cppClass,
-                                   const AbstractMetaFunctionCPtr &func, bool indexed)
+static bool containsFunctionDirective(const DocModification &dm)
 {
-    s << functionSignature(cppClass, func);
+    return dm.mode() != TypeSystem::DocModificationXPathReplace
+        && dm.code().contains(".. py:"_L1);
+}
 
-    {
+void QtDocGenerator::writeFunctions(TextStream &s, const AbstractMetaFunctionCList &funcs,
+                                    const AbstractMetaClassCPtr &cppClass, const QString &scope)
+{
+    QString lastName;
+    for (const auto &func : funcs) {
+        const bool indexed = func->name() != lastName;
+        lastName = func->name();
+        writeFunction(s, func, cppClass, scope, indexed);
+    }
+}
+
+void QtDocGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func,
+                                   const AbstractMetaClassCPtr &cppClass,
+                                   const QString &scope, bool indexed)
+{
+    const auto modifications = DocParser::getDocModifications(func, cppClass);
+
+    // Enable injecting parameter documentation by adding a complete function directive.
+    if (std::none_of(modifications.cbegin(), modifications.cend(), containsFunctionDirective)) {
+        if (func->ownerClass() == nullptr)
+            s << ".. py:function:: ";
+        else
+            s << (func->isStatic() ? ".. py:staticmethod:: " : ".. py:method:: ");
+        s << getFuncName(func) << formatArgs(func);
         Indentation indentation(s);
         if (!indexed)
             s << "\n:noindex:";
-        if (func->attributes().testFlag(AbstractMetaFunction::Attribute::FinalCppMethod))
+        if (func->cppAttributes().testFlag(FunctionAttribute::Final))
             s << "\n:final:";
         else if (func->isAbstract())
             s << "\n:abstractmethod:";
@@ -853,16 +906,12 @@ void QtDocGenerator::writeFunction(TextStream &s, const AbstractMetaClassCPtr &c
         if (func->isDeprecated())
             s << rstDeprecationNote("function");
     }
-    writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, cppClass, func);
-    if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, cppClass, func)) {
-        writeFormattedBriefText(s, func->documentation(), cppClass);
-        writeFormattedDetailedText(s, func->documentation(), cppClass);
-    }
-    writeInjectDocumentation(s, TypeSystem::DocModificationAppend, cppClass, func);
+
+    writeFunctionDocumentation(s, func, modifications, scope);
 
     if (auto propIndex = func->propertySpecIndex(); propIndex >= 0) {
         const QString name = cppClass->propertySpecs().at(propIndex).name();
-        const QString target = propertyRefTarget(cppClass, name);
+        const QString target = propertyRefTarget(name);
         if (func->isPropertyReader())
             s << "\nGetter of property " << propRef(target) << " .\n\n";
         else if (func->isPropertyWriter())
@@ -874,23 +923,79 @@ void QtDocGenerator::writeFunction(TextStream &s, const AbstractMetaClassCPtr &c
     }
 }
 
-static void writeFancyToc(TextStream& s, const QStringList& items)
+void QtDocGenerator::writeFunctionDocumentation(TextStream &s, const AbstractMetaFunctionCPtr &func,
+                                                const DocModificationList &modifications,
+                                                const QString &scope) const
+
+{
+    writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, modifications, func, scope);
+    if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, modifications, func, scope)) {
+        writeFormattedBriefText(s, func->documentation(), scope);
+        writeFormattedDetailedText(s, func->documentation(), scope);
+    }
+    writeInjectDocumentation(s, TypeSystem::DocModificationAppend, modifications, func, scope);
+}
+
+static QStringList fileListToToc(const QStringList &items)
+{
+    QStringList result;
+    result.reserve(items.size());
+    std::transform(items.cbegin(), items.cend(), std::back_inserter(result),
+                   fileNameToTocEntry);
+    return result;
+}
+
+static QStringList functionListToToc(const AbstractMetaFunctionCList &functions)
+{
+    QStringList result;
+    result.reserve(functions.size());
+    for (const auto &f : functions)
+        result.append(f->name());
+    // Functions are sorted by the Metabuilder; erase overloads
+    result.erase(std::unique(result.begin(), result.end()), result.end());
+    return result;
+}
+
+static QStringList enumListToToc(const AbstractMetaEnumList &enums)
+{
+    QStringList result;
+    result.reserve(enums.size());
+    for (const auto &e : enums)
+        result.append(e.name());
+    return result;
+}
+
+// Sort entries for a TOC by first character, dropping the
+// leading common Qt prefixes like 'Q'.
+static QChar sortKey(const QString &key)
+{
+    const auto size = key.size();
+    if (size >= 2 && (key.at(0) == u'Q' || key.at(0) == u'q')
+        && (key.at(1).isUpper() || key.at(1).isDigit())) {
+        return key.at(1); // "QClass" -> 'C', "qSin()" -> 'S', 'Q3DSurfaceWidget' -> '3'
+    }
+    if (size >= 3 && key.startsWith("Q_"_L1))
+        return key.at(2).toUpper(); // "Q_ARG" -> 'A'
+    if (size >= 4 && key.startsWith("QT_"_L1))
+        return key.at(3).toUpper(); // "QT_TR" -> 'T'
+    auto idx = 0;
+    for (; idx < size && key.at(idx) == u'_'; ++idx) {
+    } // "__init__" -> 'I'
+    return idx < size ? key.at(idx).toUpper() : u'A';
+}
+
+static void writeFancyToc(TextStream& s, QAnyStringView title,
+                          const QStringList& items,
+                          QLatin1StringView referenceType)
 {
     using TocMap = QMap<QChar, QStringList>;
+
+    if (items.isEmpty())
+        return;
+
     TocMap tocMap;
-    QChar idx;
-    for (QString item : items) {
-        if (item.isEmpty())
-            continue;
-        item.chop(4); // Remove the .rst extension
-        // skip namespace if necessary
-        const QString className = item.split(u'.').last();
-        if (className.startsWith(u'Q') && className.length() > 1)
-            idx = className[1];
-        else
-            idx = className[0];
-        tocMap[idx] << item;
-    }
+    for (const QString &item : items)
+        tocMap[sortKey(item)] << item;
 
     static const qsizetype numColumns = 4;
 
@@ -905,7 +1010,7 @@ static void writeFancyToc(TextStream& s, const QStringList& items)
                 row.clear();
                 row << QtXmlToSphinx::TableCell(QString{});
             }
-            const QString entry = u"* :doc:`"_s + item + u'`';
+            const QString entry = "* :"_L1 + referenceType + ":`"_L1 + item + u'`';
             row << QtXmlToSphinx::TableCell(entry);
         }
         if (row.size() > 1)
@@ -913,13 +1018,24 @@ static void writeFancyToc(TextStream& s, const QStringList& items)
     }
 
     table.normalize();
-    s << ".. container:: pysidetoc\n\n";
+    s << '\n' << headline(title) << ".. container:: pysidetoc\n\n";
     table.format(s);
 }
 
 bool QtDocGenerator::finishGeneration()
 {
-    if (!api().classes().isEmpty())
+    for (const auto &f : api().globalFunctions()) {
+        auto ncf = std::const_pointer_cast<AbstractMetaFunction>(f);
+        m_docParser->fillGlobalFunctionDocumentation(ncf);
+        m_packages[f->targetLangPackage()].globalFunctions.append(f);
+    }
+
+    for (auto e : api().globalEnums()) {
+        m_docParser->fillGlobalEnumDocumentation(e);
+        m_packages[e.typeEntry()->targetLangPackage()].globalEnums.append(e);
+    }
+
+    if (!m_packages.isEmpty())
         writeModuleDocumentation();
     if (!m_options.additionalDocumentationList.isEmpty())
         writeAdditionalDocumentation();
@@ -950,11 +1066,22 @@ bool QtDocGenerator::writeInheritanceFile()
     return true;
 }
 
+// Remove function entries that have extra documentation pages
+static inline void removeExtraDocs(const QStringList &extraTocEntries,
+                                   AbstractMetaFunctionCList *functions)
+{
+    auto predicate = [&extraTocEntries](const AbstractMetaFunctionCPtr &f) {
+        return extraTocEntries.contains(f->name());
+    };
+    functions->erase(std::remove_if(functions->begin(),functions->end(), predicate),
+                     functions->end());
+}
+
 void QtDocGenerator::writeModuleDocumentation()
 {
-    QMap<QString, QStringList>::iterator it = m_packages.begin();
-    for (; it != m_packages.end(); ++it) {
-        std::sort(it.value().begin(), it.value().end());
+    for (auto it = m_packages.begin(), end = m_packages.end(); it != end; ++it) {
+        auto &docPackage = it.value();
+        std::sort(docPackage.classPages.begin(), docPackage.classPages.end());
 
         QString key = it.key();
         key.replace(u'.', u'/');
@@ -963,9 +1090,7 @@ void QtDocGenerator::writeModuleDocumentation()
         TextStream& s = output.stream;
 
         const QString &title = it.key();
-        s << ".. module:: " << title << "\n\n"
-            << title << '\n'
-            << Pad('*', title.length()) << "\n\n";
+        s << ".. module:: " << title << "\n\n" << headline(title, '*');
 
         // Store the it.key() in a QString so that it can be stripped off unwanted
         // information when neeeded. For example, the RST files in the extras directory
@@ -976,6 +1101,7 @@ void QtDocGenerator::writeModuleDocumentation()
             moduleName.remove(0, lastIndex + 1);
 
         // Search for extra-sections
+        QStringList extraTocEntries;
         if (!m_options.extraSectionDir.isEmpty()) {
             QDir extraSectionDir(m_options.extraSectionDir);
             if (!extraSectionDir.exists()) {
@@ -988,28 +1114,23 @@ void QtDocGenerator::writeModuleDocumentation()
             const QString filter = moduleName + u".?*.rst"_s;
             const auto fileList =
                 extraSectionDir.entryInfoList({filter}, QDir::Files, QDir::Name);
-            for (const auto &fi : fileList) {
-                // Strip to "Property.rst" in output directory
-                const QString newFileName = fi.fileName().mid(moduleName.size() + 1);
-                it.value().append(newFileName);
-                const QString newFilePath = outputDir + u'/' + newFileName;
-                if (QFile::exists(newFilePath))
-                    QFile::remove(newFilePath);
-                if (!QFile::copy(fi.absoluteFilePath(), newFilePath)) {
-                    qCDebug(lcShibokenDoc).noquote().nospace() << "Error copying extra doc "
-                        << QDir::toNativeSeparators(fi.absoluteFilePath())
-                        << " to " << QDir::toNativeSeparators(newFilePath);
-                }
-            }
+            for (const auto &fi : fileList)
+                readExtraDoc(fi, moduleName, outputDir, &docPackage, &extraTocEntries);
         }
 
+        removeExtraDocs(extraTocEntries, &docPackage.globalFunctions);
+        const bool hasGlobals = !docPackage.globalFunctions.isEmpty()
+                                || !docPackage.globalEnums.isEmpty();
+        const QString globalsPage = moduleName + "_globals.rst"_L1;
+
         s << ".. container:: hide\n\n" << indent
             << ".. toctree::\n" << indent
             << ":maxdepth: 1\n\n";
-        for (const QString &className : std::as_const(it.value()))
+        if (hasGlobals)
+            s << globalsPage << '\n';
+        for (const QString &className : std::as_const(docPackage.classPages))
             s << className << '\n';
-        s << "\n\n" << outdent << outdent
-            << "Detailed Description\n--------------------\n\n";
+        s << "\n\n" << outdent << outdent << headline("Detailed Description");
 
         // module doc is always wrong and C++istic, so go straight to the extra directory!
         QFile moduleDoc(m_options.extraSectionDir + u'/' + moduleName
@@ -1030,14 +1151,43 @@ void QtDocGenerator::writeModuleDocumentation()
             }
         }
 
-        s << "\nList of Classes\n"
-            << "---------------\n\n";
-        writeFancyToc(s, it.value());
+        writeFancyToc(s, "List of Classes", fileListToToc(docPackage.classPages),
+                      "class"_L1);
+        writeFancyToc(s, "List of Decorators", fileListToToc(docPackage.decoratorPages),
+                      "deco"_L1);
+        writeFancyToc(s, "List of Functions", functionListToToc(docPackage.globalFunctions),
+                      "py:func"_L1);
+        writeFancyToc(s, "List of Enumerations", enumListToToc(docPackage.globalEnums),
+                      "any"_L1);
 
         output.done();
+
+        if (hasGlobals)
+            writeGlobals(it.key(), outputDir + u'/' + globalsPage, docPackage);
     }
 }
 
+void QtDocGenerator::writeGlobals(const QString &package,
+                                  const QString &fileName,
+                                  const DocPackage &docPackage)
+{
+    FileOut output(fileName);
+    TextStream &s = output.stream;
+
+    // Write out functions with injected documentation
+    if (!docPackage.globalFunctions.isEmpty()) {
+        s << currentModule(package) << headline("Functions");
+        writeFunctions(s, docPackage.globalFunctions, {}, {});
+    }
+
+    if (!docPackage.globalEnums.isEmpty()) {
+        s << headline("Enumerations");
+        writeEnums(s, docPackage.globalEnums, package);
+    }
+
+    output.done();
+}
+
 static inline QString msgNonExistentAdditionalDocFile(const QString &dir,
                                                       const QString &fileName)
 {
@@ -1075,8 +1225,8 @@ void QtDocGenerator::writeAdditionalDocumentation() const
                 targetDir = outDir.absolutePath();
             } else {
                 if (!outDir.exists(dir) && !outDir.mkdir(dir)) {
-                    const QString m = QStringLiteral("Cannot create directory ")
-                                      + dir + QStringLiteral(" under ")
+                    const QString m = "Cannot create directory "_L1
+                                      + dir + " under "_L1
                                       + QDir::toNativeSeparators(outputDirectory());
                     throw Exception(m);
                 }
@@ -1162,7 +1312,7 @@ QList<OptionDescription> QtDocGenerator::options()
          u"Directory used to search for extra documentation sections"_s},
         {u"library-source-dir=<dir>"_s,
          u"Directory where library source code is located"_s},
-        {additionalDocumentationOption() + u"=<file>"_s,
+        {additionalDocumentationOption + u"=<file>"_s,
          u"List of additional XML files to be converted to .rst files\n"
           "(for example, tutorials)."_s},
         {u"inheritance-file=<file>"_s,
@@ -1230,7 +1380,7 @@ bool QtDocGeneratorOptionsParser::handleOption(const QString &key, const QString
             m_options->doxygen = true;
         return true;
     }
-    if (key == additionalDocumentationOption()) {
+    if (key == additionalDocumentationOption) {
         m_options->additionalDocumentationList = value;
         return true;
     }
@@ -1275,16 +1425,10 @@ GeneratorDocumentation
     GeneratorDocumentation result;
     const auto allFunctions = cppClass->functions();
     result.allFunctions.reserve(allFunctions.size());
-    for (const auto &func : allFunctions) {
-        if (!shouldSkip(func)) {
-            if (func->isConstructor())
-                result.constructors.append(func);
-            else
-                result.allFunctions.append(func);
-        }
-    }
+    std::remove_copy_if(allFunctions.cbegin(), allFunctions.cend(),
+                        std::back_inserter(result.allFunctions), shouldSkip);
 
-    std::sort(result.allFunctions.begin(), result.allFunctions.end(), functionSort);
+    std::stable_sort(result.allFunctions.begin(), result.allFunctions.end(), functionSort);
 
     for (const auto &func : std::as_const(result.allFunctions)) {
         if (func->isStatic())
@@ -1409,7 +1553,7 @@ QtXmlToSphinxLink QtDocGenerator::resolveLink(const QtXmlToSphinxLink &link) con
 {
     if (link.type != QtXmlToSphinxLink::Reference || !isRelativeHtmlFile(link.linkRef))
         return link;
-    static const QString prefix = QStringLiteral("https://doc.qt.io/qt-")
+    static const QString prefix = "https://doc.qt.io/qt-"_L1
         + QString::number(QT_VERSION_MAJOR) + u'/';
     QtXmlToSphinxLink resolved = link;
     resolved.type = QtXmlToSphinxLink::External;
index 094a9326de11585e19fb181d99b86445c8fda258..3b1c82e74485d877809d6e2c77ed48fcc81925e1 100644 (file)
@@ -17,6 +17,7 @@
 class DocParser;
 struct DocGeneratorOptions;
 struct GeneratorDocumentation;
+struct DocPackage;
 
 /**
 *   The DocGenerator generates documentation from library being binded.
@@ -59,46 +60,52 @@ protected:
     bool finishGeneration() override;
 
 private:
-    void writeEnums(TextStream &s, const AbstractMetaClassCPtr &cppClass) const;
+    void writeEnums(TextStream &s, const AbstractMetaEnumList &enums,
+                    const QString &scope) const;
 
     void writeFields(TextStream &s, const AbstractMetaClassCPtr &cppClass) const;
-    static QString functionSignature(const AbstractMetaClassCPtr &cppClass,
-                                     const AbstractMetaFunctionCPtr &func);
-    void writeFunction(TextStream &s, const AbstractMetaClassCPtr &cppClass,
-                       const AbstractMetaFunctionCPtr &func, bool indexed = true);
+    void writeFunctions(TextStream &s, const AbstractMetaFunctionCList &funcs,
+                        const AbstractMetaClassCPtr &cppClass, const QString &scope);
+    void writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func,
+                       const AbstractMetaClassCPtr &cppClass = {},
+                       const QString &scope = {}, bool indexed = true);
+    void writeFunctionDocumentation(TextStream &s, const AbstractMetaFunctionCPtr &func,
+                                    const DocModificationList &modifications,
+                                    const QString &scope) const;
     void writeFunctionParametersType(TextStream &s, const AbstractMetaClassCPtr &cppClass,
                                      const AbstractMetaFunctionCPtr &func) const;
     static void writeFunctionToc(TextStream &s, const QString &title,
-                                 const AbstractMetaClassCPtr &cppClass,
                                  const AbstractMetaFunctionCList &functions);
     static void writePropertyToc(TextStream &s,
-                                 const GeneratorDocumentation &doc,
-                                 const AbstractMetaClassCPtr &cppClass);
+                                 const GeneratorDocumentation &doc);
     void writeProperties(TextStream &s,
                          const GeneratorDocumentation &doc,
                          const AbstractMetaClassCPtr &cppClass) const;
     void writeParameterType(TextStream &s, const AbstractMetaClassCPtr &cppClass,
                             const AbstractMetaArgument &arg) const;
-
-    void writeConstructors(TextStream &s,
-                           const AbstractMetaClassCPtr &cppClass,
-                           const AbstractMetaFunctionCList &constructors) const;
-
     void writeFormattedText(TextStream &s, const QString &doc,
                             Documentation::Format format,
-                            const AbstractMetaClassCPtr &metaClass = {}) const;
+                            const QString &scope = {}) const;
     void writeFormattedBriefText(TextStream &s, const Documentation &doc,
-                                 const AbstractMetaClassCPtr &metaclass = {}) const;
+                                 const QString &scope = {}) const;
     void writeFormattedDetailedText(TextStream &s, const Documentation &doc,
-                                    const AbstractMetaClassCPtr &metaclass = {}) const;
+                                    const QString &scope = {}) const;
 
     bool writeInjectDocumentation(TextStream &s, TypeSystem::DocModificationMode mode,
-                                  const AbstractMetaClassCPtr &cppClass,
-                                  const AbstractMetaFunctionCPtr &func);
+                                  const AbstractMetaClassCPtr &cppClass) const;
+    bool writeInjectDocumentation(TextStream &s, TypeSystem::DocModificationMode mode,
+                                  const DocModificationList &modifications,
+                                  const AbstractMetaFunctionCPtr &func,
+                                  const QString &scope = {}) const;
+    bool writeDocModifications(TextStream &s, const DocModificationList &mods,
+                               TypeSystem::DocModificationMode mode,
+                               const QString &scope = {}) const;
     static void writeDocSnips(TextStream &s, const CodeSnipList &codeSnips,
                               TypeSystem::CodeSnipPosition position, TypeSystem::Language language);
 
     void writeModuleDocumentation();
+    void writeGlobals(const QString &package, const QString &fileName,
+                      const DocPackage &docPackage);
     void writeAdditionalDocumentation() const;
     bool writeInheritanceFile();
 
@@ -114,7 +121,7 @@ private:
     static GeneratorDocumentation generatorDocumentation(const AbstractMetaClassCPtr &cppClass);
 
     QStringList m_functionList;
-    QMap<QString, QStringList> m_packages;
+    QMap<QString, DocPackage> m_packages;
     QScopedPointer<DocParser> m_docParser;
     static DocGeneratorOptions m_options;
 };
index b129a453e93f4ccf0d3edfdc0b369962ba953888..55c1d2090f1beb517ec63c8b815c6775211d126d 100644 (file)
 
 using namespace Qt::StringLiterals;
 
-static inline QString nameAttribute() { return QStringLiteral("name"); }
-static inline QString titleAttribute() { return QStringLiteral("title"); }
-static inline QString fullTitleAttribute() { return QStringLiteral("fulltitle"); }
-
 QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
                       const QString &tag, const QString &message)
 {
@@ -445,13 +441,13 @@ QString QtXmlToSphinx::popOutputBuffer()
     return result;
 }
 
-static const QString autoTranslatedPlaceholder = u"AUTO_GENERATED\n"_s;
-static const QString autoTranslatedNote =
-uR"(.. warning::
+constexpr auto autoTranslatedPlaceholder = "AUTO_GENERATED\n"_L1;
+constexpr auto autoTranslatedNote =
+R"(.. warning::
     This section contains snippets that were automatically
     translated from C++ to Python and may contain errors.
 
-)"_s;
+)"_L1;
 
 void QtXmlToSphinx::setAutoTranslatedNote(QString *str) const
 {
@@ -778,9 +774,9 @@ void QtXmlToSphinx::handleParaTagEnd()
 {
     QString result = popOutputBuffer().simplified();
     if (result.startsWith(u"**Warning:**"))
-        result.replace(0, 12, QStringLiteral(".. warning:: "));
+        result.replace(0, 12, ".. warning:: "_L1);
     else if (result.startsWith(u"**Note:**"))
-        result.replace(0, 9, QStringLiteral(".. note:: "));
+        result.replace(0, 9, ".. note:: "_L1);
     m_output << result << "\n\n";
 }
 
@@ -849,23 +845,23 @@ void QtXmlToSphinx::handleArgumentTag(QXmlStreamReader& reader)
     }
 }
 
-static inline QString functionLinkType() { return QStringLiteral("function"); }
-static inline QString classLinkType() { return QStringLiteral("class"); }
+constexpr auto functionLinkType = "function"_L1;
+constexpr auto classLinkType = "class"_L1;
 
 static inline QString fixLinkType(QStringView type)
 {
     // TODO: create a flag PROPERTY-AS-FUNCTION to ask if the properties
     // are recognized as such or not in the binding
     if (type == u"property")
-        return functionLinkType();
+        return functionLinkType;
     if (type == u"typedef")
-        return classLinkType();
+        return classLinkType;
     return type.toString();
 }
 
 static inline QString linkSourceAttribute(const QString &type)
 {
-    if (type == functionLinkType() || type == classLinkType())
+    if (type == functionLinkType || type == classLinkType)
         return u"raw"_s;
     return type == u"enum" || type == u"page"
         ? type : u"href"_s;
@@ -891,7 +887,7 @@ void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader)
             const QString text = textR.toString();
             if (m_seeAlsoContext.isNull()) {
                 const QString type = text.endsWith(u"()")
-                    ? functionLinkType() : classLinkType();
+                    ? functionLinkType : classLinkType;
                 m_seeAlsoContext.reset(handleLinkStart(type, text));
             }
             handleLinkText(m_seeAlsoContext.data(), text);
@@ -910,7 +906,7 @@ void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader)
     }
 }
 
-static inline QString fallbackPathAttribute() { return QStringLiteral("path"); }
+constexpr auto fallbackPathAttribute = "path"_L1;
 
 template <class Indent> // const char*/class Indentor
 void formatSnippet(TextStream &str, Indent indent, const QString &snippet)
@@ -950,8 +946,8 @@ void QtXmlToSphinx::handleSnippetTag(QXmlStreamReader& reader)
         QString location = reader.attributes().value(u"location"_s).toString();
         QString identifier = reader.attributes().value(u"identifier"_s).toString();
         QString fallbackPath;
-        if (reader.attributes().hasAttribute(fallbackPathAttribute()))
-            fallbackPath = reader.attributes().value(fallbackPathAttribute()).toString();
+        if (reader.attributes().hasAttribute(fallbackPathAttribute))
+            fallbackPath = reader.attributes().value(fallbackPathAttribute).toString();
         QString errorMessage;
 
         const Snippet snippet = readSnippetFromLocations(location, identifier,
@@ -1165,7 +1161,7 @@ QtXmlToSphinxLink *QtXmlToSphinx::handleLinkStart(const QString &type, QString r
 
     if (type == u"external" || isHttpLink(ref)) {
         result->type = QtXmlToSphinxLink::External;
-    } else if (type == functionLinkType() && !m_context.isEmpty()) {
+    } else if (type == functionLinkType && !m_context.isEmpty()) {
         result->type = QtXmlToSphinxLink::Method;
         const auto rawlinklist = QStringView{result->linkRef}.split(u'.');
         if (rawlinklist.size() == 1 || rawlinklist.constFirst() == m_context) {
@@ -1176,9 +1172,9 @@ QtXmlToSphinxLink *QtXmlToSphinx::handleLinkStart(const QString &type, QString r
         } else {
             result->linkRef = m_generator->expandFunction(result->linkRef);
         }
-    } else if (type == functionLinkType() && m_context.isEmpty()) {
+    } else if (type == functionLinkType && m_context.isEmpty()) {
         result->type = QtXmlToSphinxLink::Function;
-    } else if (type == classLinkType()) {
+    } else if (type == classLinkType) {
         result->type = QtXmlToSphinxLink::Class;
         result->linkRef = m_generator->expandClass(m_context, result->linkRef);
     } else if (type == u"enum") {
@@ -1397,11 +1393,11 @@ void QtXmlToSphinx::handlePageTag(QXmlStreamReader &reader)
 
     m_output << disableIndent;
 
-    const auto  title = reader.attributes().value(titleAttribute());
+    const auto  title = reader.attributes().value("title");
     if (!title.isEmpty())
         m_output << rstLabel(title.toString());
 
-    const auto  fullTitle = reader.attributes().value(fullTitleAttribute());
+    const auto  fullTitle = reader.attributes().value("fulltitle");
     const int size = fullTitle.isEmpty()
        ? writeEscapedRstText(m_output, title)
        : writeEscapedRstText(m_output, fullTitle);
@@ -1414,7 +1410,7 @@ void QtXmlToSphinx::handleTargetTag(QXmlStreamReader &reader)
 {
     if (reader.tokenType() != QXmlStreamReader::StartElement)
         return;
-    const auto  name = reader.attributes().value(nameAttribute());
+    const auto  name = reader.attributes().value("name");
     if (!name.isEmpty())
         m_output << rstLabel(name.toString());
 }
index 1f3c68ddd661e2f7443c664f038dd5c1cd6862d7..a7013aded14fc9a63966e73292ea19cfd5d47b3b 100644 (file)
@@ -58,6 +58,11 @@ using namespace Qt::StringLiterals;
 
 static const char shibokenErrorsOccurred[] = "Shiboken::Errors::occurred() != nullptr";
 
+static constexpr auto virtualMethodStaticReturnVar = "result"_L1;
+
+static constexpr auto sbkObjectTypeF = "SbkObject_TypeF()"_L1;
+static const char initInheritanceFunction[] = "initInheritance";
+
 static QString mangleName(QString name)
 {
     if (name == u"None" || name == u"False" || name == u"True" || name == u"from")
@@ -67,9 +72,9 @@ static QString mangleName(QString name)
 
 struct sbkUnusedVariableCast
 {
-    explicit sbkUnusedVariableCast(QStringView name) : m_name(name) {}
+    explicit sbkUnusedVariableCast(QAnyStringView name) : m_name(name) {}
 
-    const QStringView m_name;
+    const QAnyStringView m_name;
 };
 
 TextStream &operator<<(TextStream &str, const sbkUnusedVariableCast &c)
@@ -78,6 +83,24 @@ TextStream &operator<<(TextStream &str, const sbkUnusedVariableCast &c)
     return str;
 }
 
+struct pyTypeGetSlot
+{
+    explicit pyTypeGetSlot(QAnyStringView funcType, QAnyStringView typeObject,
+                           QAnyStringView aSlot) :
+        m_funcType(funcType), m_typeObject(typeObject), m_slot(aSlot) {}
+
+    const QAnyStringView m_funcType;
+    const QAnyStringView m_typeObject;
+    const QAnyStringView m_slot;
+};
+
+TextStream &operator<<(TextStream &str, const pyTypeGetSlot &p)
+{
+    str << "reinterpret_cast<" << p.m_funcType << ">(PepType_GetSlot("
+        << p.m_typeObject << ", " << p.m_slot << "));\n";
+    return str;
+}
+
 TextStream &operator<<(TextStream &s, CppGenerator::ErrorReturn r)
 {
     s << "return";
@@ -98,6 +121,25 @@ TextStream &operator<<(TextStream &s, CppGenerator::ErrorReturn r)
     return s;
 }
 
+static constexpr auto converterVar = "converter"_L1;
+
+struct registerConverterName
+{
+    explicit registerConverterName(QAnyStringView typeName,
+                                   QAnyStringView varName = converterVar) :
+        m_typeName(typeName), m_varName(varName) {}
+
+    QAnyStringView m_typeName;
+    QAnyStringView m_varName;
+};
+
+TextStream &operator<<(TextStream &s, const registerConverterName &r)
+{
+    s << "Shiboken::Conversions::registerConverterName(" << r.m_varName
+        <<  ", \"" << r.m_typeName << "\");\n";
+    return s;
+}
+
 // Protocol function name / function parameters / return type
 struct ProtocolEntry
 {
@@ -130,7 +172,7 @@ const ProtocolEntries &mappingProtocols()
          u"PyObject*"_s},
         {u"__msetitem__"_s,
          u"PyObject *self, PyObject *_key, PyObject *_value"_s,
-         intT()}};
+         intT}};
     return result;
 }
 
@@ -147,16 +189,16 @@ const ProtocolEntries &sequenceProtocols()
          u"PyObject*"_s},
         {u"__setitem__"_s,
          u"PyObject *self, Py_ssize_t _i, PyObject *_value"_s,
-         intT()},
+         intT},
         {u"__getslice__"_s,
          u"PyObject *self, Py_ssize_t _i1, Py_ssize_t _i2"_s,
          u"PyObject*"_s},
         {u"__setslice__"_s,
          u"PyObject *self, Py_ssize_t _i1, Py_ssize_t _i2, PyObject *_value"_s,
-         intT()},
+         intT},
         {u"__contains__"_s,
          u"PyObject *self, PyObject *_value"_s,
-         intT()},
+         intT},
         {u"__concat__"_s,
          u"PyObject *self, PyObject *_other"_s,
          u"PyObject*"_s}
@@ -579,13 +621,15 @@ void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classCon
                 writeVirtualMethodNative(s, func, maxOverrides++);
         }
 
-        if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) {
-            if (usePySideExtensions() && isQObject(metaClass))
-                writeMetaObjectMethod(s, classContext);
+        if (shouldGenerateMetaObjectFunctions(metaClass))
+            writeMetaObjectMethod(s, classContext);
+        if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
             writeDestructorNative(s, classContext);
-        }
     }
 
+    for (const auto &f : metaClass->userAddedPythonOverrides())
+        writeUserAddedPythonOverride(s, f);
+
     StringStream smd(TextStream::Language::Cpp);
     StringStream md(TextStream::Language::Cpp);
     StringStream signatureStream(TextStream::Language::Cpp);
@@ -932,17 +976,24 @@ void CppGenerator::writeVirtualMethodCppCall(TextStream &s,
 }
 
 // Determine the return statement (void or a result value).
-QString CppGenerator::virtualMethodReturn(TextStream &s, const ApiExtractorResult &api,
-                                          const AbstractMetaFunctionCPtr &func,
-                                          const FunctionModificationList &functionModifications)
+
+CppGenerator::VirtualMethodReturn
+    CppGenerator::virtualMethodReturn(const ApiExtractorResult &api,
+                                      const AbstractMetaFunctionCPtr &func,
+                                      const FunctionModificationList &functionModifications)
 {
-    if (func->isVoid())
-        return u"return;"_s;
+    VirtualMethodReturn result;
+    if (func->isVoid()) {
+        result.statement = "return;"_L1;
+        return result;
+    }
+
+    result.statement = "return "_L1;
     const AbstractMetaType &returnType = func->type();
     for (const FunctionModification &mod : functionModifications) {
         for (const ArgumentModification &argMod : mod.argument_mods()) {
             if (argMod.index() == 0 && !argMod.replacedDefaultExpression().isEmpty()) {
-                static const QRegularExpression regex(QStringLiteral("%(\\d+)"));
+                static const QRegularExpression regex("%(\\d+)"_L1);
                 Q_ASSERT(regex.isValid());
                 QString expr = argMod.replacedDefaultExpression();
                 for (int offset = 0; ; ) {
@@ -958,8 +1009,8 @@ QString CppGenerator::virtualMethodReturn(TextStream &s, const ApiExtractorResul
                     offset = match.capturedStart(1);
                 }
                 DefaultValue defaultReturnExpr(DefaultValue::Custom, expr);
-                return u"return "_s + defaultReturnExpr.returnValue()
-                       + u';';
+                result.statement += defaultReturnExpr.returnValue() + u';';
+                return result;
             }
         }
     }
@@ -971,16 +1022,13 @@ QString CppGenerator::virtualMethodReturn(TextStream &s, const ApiExtractorResul
         errorMsg = msgCouldNotFindMinimalConstructor(errorMsg,
                                                      func->type().cppSignature(),
                                                      errorMessage);
-        qCWarning(lcShiboken).noquote().nospace() << errorMsg;
-        s  << "\n#error " << errorMsg << '\n';
-    }
-    if (returnType.referenceType() == LValueReference) {
-        s << "static " << returnType.typeEntry()->qualifiedCppName()
-            << " result;\n";
-        return u"return result;"_s;
+        throw Exception(errorMsg);
     }
-    return u"return "_s + defaultReturnExpr->returnValue()
-           + u';';
+
+    result.needsReference = returnType.referenceType() == LValueReference;
+    result.statement += (result.needsReference
+        ? virtualMethodStaticReturnVar : defaultReturnExpr->returnValue()) + u';';
+    return result;
 }
 
 // Create an argument for Py_BuildValue() when writing virtual methods.
@@ -1073,13 +1121,42 @@ static bool isArgumentNotRemoved(const AbstractMetaArgument &a)
 
 // PyObject_Vectorcall(): since 3.9
 static const char vectorCallCondition[] =
-    "#if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x03090000\n";
+    "#if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API)\n";
 
 // PyObject_CallNoArgs(): since 3.9, stable API since 3.10
 static const char noArgsCallCondition[] =
-    "#if !defined(PYPY_VERSION) && ((defined(Py_LIMITED_API) && Py_LIMITED_API >= 0x030A0000) || (!defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x03090000))\n";
+    "#if !defined(PYPY_VERSION) && ((defined(Py_LIMITED_API) && Py_LIMITED_API >= 0x030A0000) || !defined(Py_LIMITED_API))\n";
 static const char inverseNoArgsCallCondition[] =
-    "#if defined(PYPY_VERSION) || (defined(Py_LIMITED_API) && Py_LIMITED_API < 0x030A0000) || (!defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x03090000)\n";
+    "#if defined(PYPY_VERSION) || (defined(Py_LIMITED_API) && Py_LIMITED_API < 0x030A0000)\n";
+
+static inline void writeVirtualMethodStaticReturnVar(TextStream &s, const AbstractMetaFunctionCPtr &func)
+{
+    s << "static " << func->type().typeEntry()->qualifiedCppName() << ' '
+        << virtualMethodStaticReturnVar << ";\n";
+}
+
+static void writeFuncNameVar(TextStream &s, const AbstractMetaFunctionCPtr &func,
+                             const QString &funcName)
+{
+    // PYSIDE-1019: Add info about properties
+    int propFlag = 0;
+    if (func->isPropertyReader())
+        propFlag |= 1;
+    if (func->isPropertyWriter())
+        propFlag |= 2;
+    if (propFlag && func->isStatic())
+        propFlag |= 4;
+    QString propStr;
+    if (propFlag != 90)
+        propStr = QString::number(propFlag) + u':';
+
+    if (propFlag != 0)
+        s << "// This method belongs to a property.\n";
+    s << "static const char *funcName = \"";
+    if (propFlag != 0)
+        s << propFlag << ':';
+    s << funcName << "\";\n";
+}
 
 void CppGenerator::writeVirtualMethodNative(TextStream &s,
                                             const AbstractMetaFunctionCPtr &func,
@@ -1094,13 +1171,16 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
                                                     Generator::OriginalTypeDescription)
       << "\n{\n" << indent;
 
-    const QString returnStatement = virtualMethodReturn(s, api(), func,
-                                                        func->modifications());
+    const auto returnStatement = virtualMethodReturn(api(), func,
+                                                     func->modifications());
+
+    if (returnStatement.needsReference)
+        writeVirtualMethodStaticReturnVar(s, func);
 
     const bool isAbstract = func->isAbstract();
     if (isAbstract && func->isModifiedRemoved()) {
         qCWarning(lcShiboken, "%s", qPrintable(msgPureVirtualFunctionRemoved(func.get())));
-        s << returnStatement << '\n' << outdent << "}\n\n";
+        s << returnStatement.statement << '\n' << outdent << "}\n\n";
         return;
     }
 
@@ -1129,7 +1209,7 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
     s << "if (m_PyMethodCache[" << cacheIndex << "])" << (multi_line ? " {\n" : "\n")
         << indent;
     writeVirtualMethodCppCall(s, func, funcName, snips, lastArg, retType,
-                              returnStatement, false);
+                              returnStatement.statement, false);
     s << outdent;
     if (multi_line)
         s << "}\n";
@@ -1138,33 +1218,32 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
 
     // Get out of virtual method call if someone already threw an error.
     s << "if (" << shibokenErrorsOccurred << ")\n" << indent
-        << returnStatement << '\n' << outdent;
-
-    // PYSIDE-1019: Add info about properties
-    int propFlag = 0;
-    if (func->isPropertyReader())
-        propFlag |= 1;
-    if (func->isPropertyWriter())
-        propFlag |= 2;
-    if (propFlag && func->isStatic())
-        propFlag |= 4;
-    QString propStr;
-    if (propFlag)
-        propStr = QString::number(propFlag) + u':';
+        << returnStatement.statement << '\n' << outdent;
 
     s << "static PyObject *nameCache[2] = {};\n";
-    if (propFlag)
-        s << "// This method belongs to a property.\n";
-    s << "static const char *funcName = \"" << propStr << funcName << "\";\n"
-        << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR
+    writeFuncNameVar(s, func, funcName);
+    s << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR
         << "(Shiboken::BindingManager::instance().getOverride(this, nameCache, funcName));\n"
         << "if (" << PYTHON_OVERRIDE_VAR << ".isNull()) {\n" << indent;
     if (useOverrideCaching(func->ownerClass()))
         s << "m_PyMethodCache[" << cacheIndex << "] = true;\n";
     writeVirtualMethodCppCall(s, func, funcName, snips, lastArg, retType,
-                              returnStatement, true);
+                              returnStatement.statement, true);
     s << outdent << "}\n\n"; //WS
 
+    if (!snips.isEmpty()) {
+        writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionPyOverride,
+                       TypeSystem::ShellCode, func, false, lastArg);
+    }
+
+    writeVirtualMethodPythonOverride(s, func, snips, returnStatement);
+}
+
+void CppGenerator::writeVirtualMethodPythonOverride(TextStream &s,
+                                                    const AbstractMetaFunctionCPtr &func,
+                                                    const CodeSnipList &snips,
+                                                    const VirtualMethodReturn &returnStatement) const
+{
     writeConversionRule(s, func, TypeSystem::TargetLangCode, false);
 
     bool invalidateReturn = false;
@@ -1187,7 +1266,7 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
     auto arguments = func->arguments();
     auto removedEnd = std::stable_partition(arguments.begin(), arguments.end(),
                                             isArgumentNotRemoved);
-    if (isAbstract) { // Base function is not called, indicate unused arguments.
+    if (func->isAbstract()) { // Base function is not called, indicate unused arguments.
         for (auto it = removedEnd; it != arguments.end(); ++it)
             s << sbkUnusedVariableCast(it->name());
     }
@@ -1259,7 +1338,7 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
         s << "if (" << PYTHON_RETURN_VAR << ".isNull()) {\n" << indent
             << "// An error happened in python code!\n"
             << "Shiboken::Errors::storeErrorOrPrint();\n"
-            << returnStatement << "\n" << outdent
+            << returnStatement.statement << "\n" << outdent
         << "}\n";
 
         if (invalidateReturn) {
@@ -1271,7 +1350,7 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
 
         if (!func->isVoid()) {
 
-            if (func->modifiedTypeName() != cPyObjectT()) {
+            if (func->modifiedTypeName() != cPyObjectT) {
 
                 s << "// Check return type\n";
 
@@ -1286,7 +1365,7 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
                         << func->ownerClass()->name() << "\", funcName, "
                         << getVirtualFunctionReturnTypeName(func) << ", "
                         << "Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);\n"
-                        << returnStatement << '\n' << outdent
+                        << returnStatement.statement << '\n' << outdent
                     << "}\n";
 
                 } else {
@@ -1308,7 +1387,7 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
                         << func->ownerClass()->name() << "\", funcName, "
                         << getVirtualFunctionReturnTypeName(func) << ", "
                         << "Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);\n"
-                        << returnStatement << '\n' << outdent
+                        << returnStatement.statement << '\n' << outdent
                     << "}\n";
 
                 }
@@ -1345,6 +1424,7 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
 
     if (!func->isVoid()) {
         s << "return ";
+        TypeEntryCPtr retType = func->type().typeEntry();
         if (avoidProtectedHack() && retType->isEnum()) {
             auto metaEnum = api().findAbstractMetaEnum(retType);
             bool isProtectedEnum = metaEnum.has_value() && metaEnum->isProtected();
@@ -1365,6 +1445,28 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
     s << outdent << "}\n\n";
 }
 
+void CppGenerator::writeUserAddedPythonOverride(TextStream &s,
+                                                const AbstractMetaFunctionCPtr &func) const
+{
+    TypeEntryCPtr retType = func->type().typeEntry();
+    const QString funcName = func->isOperatorOverload()
+        ? pythonOperatorFunctionName(func) : func->definitionNames().constFirst();
+
+    const CodeSnipList snips = func->hasInjectedCode()
+        ? func->injectedCodeSnips() : CodeSnipList();
+
+    QString prefix = wrapperName(func->ownerClass()) + u"::"_s;
+    s << '\n' << functionSignature(func, prefix, QString(), Generator::SkipDefaultValues |
+                                   Generator::OriginalTypeDescription)
+      << "\n{\n" << indent << sbkUnusedVariableCast("gil");
+
+    writeFuncNameVar(s, func, funcName);
+
+    const auto returnStatement = virtualMethodReturn(api(), func,
+                                                     func->modifications());
+    writeVirtualMethodPythonOverride(s, func, snips, returnStatement);
+}
+
 void CppGenerator::writeMetaObjectMethod(TextStream &s,
                                          const GeneratorContext &classContext) const
 {
@@ -1537,7 +1639,7 @@ void CppGenerator::writeConverterFunctions(TextStream &s, const AbstractMetaClas
             << "if (pyOut) {\n" << indent
             << "Py_INCREF(pyOut);\nreturn pyOut;\n" << outdent
             << "}\n"
-            << "bool changedTypeName = false;\n"
+            << "bool exactType = false;\n"
             << "auto *tCppIn = reinterpret_cast<const " << typeName << R"( *>(cppIn);
 const char *typeName = )";
 
@@ -1547,15 +1649,11 @@ const char *typeName = )";
         else
             c << nameFunc << "(tCppIn);\n";
         c << R"(auto *sbkType = Shiboken::ObjectType::typeForTypeName(typeName);
-if (sbkType != nullptr && Shiboken::ObjectType::hasSpecialCastFunction(sbkType)) {
-    typeName = Shiboken::typeNameOf(typeid(*tCppIn).name());
-    changedTypeName = true;
-}
+if (sbkType != nullptr && Shiboken::ObjectType::hasSpecialCastFunction(sbkType))
+    exactType = true;
 )"
             << "PyObject *result = Shiboken::Object::newObject(" << cpythonType
-            << R"(, const_cast<void *>(cppIn), false, /* exactType */ changedTypeName, typeName);
-if (changedTypeName)
-    delete [] typeName;
+            << R"(, const_cast<void *>(cppIn), false, exactType, typeName);
 return result;)";
     }
     std::swap(targetTypeName, sourceTypeName);
@@ -1585,7 +1683,7 @@ return result;)";
         c << "auto *source = reinterpret_cast<const " << typeName << " *>(cppIn);\n";
     }
     c << "return Shiboken::Object::newObject(" << cpythonType
-        << ", new ::" << classContext.effectiveClassName() << '('
+        << ", new " << globalScopePrefix(classContext) << classContext.effectiveClassName() << '('
         << (isUniquePointer ? "std::move(*source)" : "*source")
         << "), true, true);";
     writeCppToPythonFunction(s, c.toString(), sourceTypeName, targetTypeName);
@@ -1595,7 +1693,7 @@ return result;)";
     s << "// Python to C++ copy conversion.\n";
     sourceTypeName = metaClass->name();
 
-    targetTypeName = sourceTypeName + QStringLiteral("_COPY");
+    targetTypeName = sourceTypeName + "_COPY"_L1;
     c.clear();
 
     QString pyInVariable = u"pyIn"_s;
@@ -1739,9 +1837,8 @@ void CppGenerator::writeConverterRegister(TextStream &s, const AbstractMetaClass
 
     auto writeConversions = [&s](const QString &signature)
     {
-        s << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "\");\n"
-            << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "*\");\n"
-            << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "&\");\n";
+        s << registerConverterName(signature) << registerConverterName(signature + u'*')
+            << registerConverterName(signature + u'&');
     };
 
     auto writeConversionsForType = [writeConversions](const QString &fullTypeName)
@@ -1773,7 +1870,7 @@ void CppGenerator::writeConverterRegister(TextStream &s, const AbstractMetaClass
         writeConversionsForType(smartPointerType);
     }
 
-    s << "Shiboken::Conversions::registerConverterName(converter, typeid(::";
+    s << "Shiboken::Conversions::registerConverterName(converter, typeid(" << m_gsp;
     QString qualifiedCppNameInvocation;
     if (!classContext.forSmartPointer())
         qualifiedCppNameInvocation = metaClass->qualifiedCppName();
@@ -1783,7 +1880,7 @@ void CppGenerator::writeConverterRegister(TextStream &s, const AbstractMetaClass
     s << qualifiedCppNameInvocation << ").name());\n";
 
     if (classContext.useWrapper()) {
-        s << "Shiboken::Conversions::registerConverterName(converter, typeid(::"
+        s << "Shiboken::Conversions::registerConverterName(converter, typeid("
             << classContext.wrapperName() << ").name());\n";
     }
 
@@ -1884,7 +1981,9 @@ void CppGenerator::writeMethodWrapperPreamble(TextStream &s,
     if (rfunc->isConstructor()) {
         // Check if the right constructor was called.
         if (!ownerClass->hasPrivateDestructor()) {
-            s << "if (Shiboken::Object::isUserType(self) && !Shiboken::ObjectType::canCallConstructor(self->ob_type, Shiboken::SbkType< ::";
+            s << "if (Shiboken::Object::isUserType(self) && "
+              << "!Shiboken::ObjectType::canCallConstructor(self->ob_type, Shiboken::SbkType< "
+              << m_gsp;
             QString qualifiedCppName;
             if (!context.forSmartPointer())
                 qualifiedCppName = ownerClass->qualifiedCppName();
@@ -1894,7 +1993,7 @@ void CppGenerator::writeMethodWrapperPreamble(TextStream &s,
             s << qualifiedCppName << " >()))\n" << indent << errorReturn << outdent << '\n';
         }
         // Declare pointer for the underlying C++ object.
-        s << "::" << context.effectiveClassName() << " *cptr{};\n";
+        s << globalScopePrefix(context) << context.effectiveClassName() << " *cptr{};\n";
 
         initPythonArguments = maxArgs > 0;
 
@@ -1957,8 +2056,8 @@ void CppGenerator::writeConstructorWrapper(TextStream &s, const OverloadData &ov
     s << cpythonFunctionName(rfunc)
         << "(PyObject *self, PyObject *args, PyObject *kwds)\n{\n" << indent;
     if (overloadData.maxArgs() == 0 || metaClass->isAbstract())
-        s << sbkUnusedVariableCast(u"args"_s);
-    s << sbkUnusedVariableCast(u"kwds"_s);
+        s << sbkUnusedVariableCast("args");
+    s << sbkUnusedVariableCast("kwds");
 
     const bool needsMetaObject = usePySideExtensions() && isQObject(metaClass);
     if (needsMetaObject)
@@ -1975,11 +2074,11 @@ void CppGenerator::writeConstructorWrapper(TextStream &s, const OverloadData &ov
     if (metaClass->isAbstract()) {
         // C++ Wrapper disabled: Abstract C++ class cannot be instantiated.
         if (metaClass->typeEntry()->typeFlags().testFlag(ComplexTypeEntry::DisableWrapper)) {
-            s << sbkUnusedVariableCast(u"sbkSelf"_s)
-                << sbkUnusedVariableCast(u"type"_s)
-                << sbkUnusedVariableCast(u"myType"_s);
+            s << sbkUnusedVariableCast("sbkSelf")
+                << sbkUnusedVariableCast("type")
+                << sbkUnusedVariableCast("myType");
             if (needsMetaObject)
-                s << sbkUnusedVariableCast(u"metaObject"_s);
+                s << sbkUnusedVariableCast("metaObject");
             s << "Shiboken::Errors::setInstantiateAbstractClassDisabledWrapper(\""
                 << metaClass->qualifiedCppName() << "\");\n" << errorReturn << outdent
                 << "}\n\n";
@@ -2026,8 +2125,8 @@ void CppGenerator::writeConstructorWrapper(TextStream &s, const OverloadData &ov
     const QString typeName = classContext.forSmartPointer()
         ? classContext.preciseType().cppSignature() : metaClass->qualifiedCppName();
     s << "if (" << shibokenErrorsOccurred
-        << " || !Shiboken::Object::setCppPointer(sbkSelf, Shiboken::SbkType< ::"
-        << typeName << " >(), cptr)) {\n"
+        << " || !Shiboken::Object::setCppPointer(sbkSelf, Shiboken::SbkType< "
+        << globalScopePrefix(classContext) << typeName << " >(), cptr)) {\n"
         <<  indent << "delete cptr;\n" << errorReturn << outdent
         << "}\n";
     if (overloadData.maxArgs() > 0)
@@ -2117,9 +2216,9 @@ void CppGenerator::writeMethodWrapper(TextStream &s, const OverloadData &overloa
     }
     s << ")\n{\n" << indent;
     if (rfunc->ownerClass() == nullptr || overloadData.hasStaticFunction())
-        s << sbkUnusedVariableCast(u"self");
+        s << sbkUnusedVariableCast(PYTHON_SELF_VAR);
     if (hasKwdArgs)
-        s << sbkUnusedVariableCast(u"kwds");
+        s << sbkUnusedVariableCast("kwds");
 
     writeMethodWrapperPreamble(s, overloadData, classContext);
 
@@ -2190,7 +2289,7 @@ void CppGenerator::writeArgumentsInitializer(TextStream &s, const OverloadData &
                                              ErrorReturn errorReturn)
 {
     const auto rfunc = overloadData.referenceFunction();
-    s << "PyTuple_GET_SIZE(args);\n" << sbkUnusedVariableCast(u"numArgs"_s);
+    s << "PyTuple_GET_SIZE(args);\n" << sbkUnusedVariableCast("numArgs");
 
     int minArgs = overloadData.minArgs();
     int maxArgs = overloadData.maxArgs();
@@ -2273,10 +2372,9 @@ void CppGenerator::writeCppSelfConversion(TextStream &s, const GeneratorContext
         return;
     }
 
-    static const QString pythonSelfVar = u"self"_s;
     if (useWrapperClass)
         s << "static_cast<" << className << " *>(";
-    s << cpythonWrapperCPtr(context.metaClass(), pythonSelfVar);
+    s << cpythonWrapperCPtr(context.metaClass(), PYTHON_SELF_VAR);
     if (useWrapperClass)
         s << ')';
 }
@@ -2311,7 +2409,7 @@ void CppGenerator::writeCppSelfDefinition(TextStream &s,
     const QString className = useWrapperClass
         ? context.wrapperName() : getFullTypeName(metaClass);
 
-    writeInvalidPyObjectCheck(s, u"self"_s, errorReturn);
+    writeInvalidPyObjectCheck(s, PYTHON_SELF_VAR, errorReturn);
 
     if (flags.testFlag(CppSelfAsReference)) {
          writeCppSelfVarDef(s, flags);
@@ -2557,12 +2655,12 @@ static inline QString arrayHandleType(const AbstractMetaTypeList &nestedArrayTyp
 {
     switch (nestedArrayTypes.size()) {
     case 1:
-        return QStringLiteral("Shiboken::Conversions::ArrayHandle<")
+        return "Shiboken::Conversions::ArrayHandle<"_L1
             + nestedArrayTypes.constLast().minimalSignature() + u'>';
     case 2:
-        return QStringLiteral("Shiboken::Conversions::Array2Handle<")
+        return "Shiboken::Conversions::Array2Handle<"_L1
             + nestedArrayTypes.constLast().minimalSignature()
-            + QStringLiteral(", ")
+            + ", "_L1
             + QString::number(nestedArrayTypes.constFirst().arrayElementCount())
             + u'>';
     }
@@ -2887,7 +2985,7 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
         int sequenceArgCount = 0;
         while (od && !od->argType().isVarargs()) {
             const bool typeReplacedByPyObject = od->isTypeModified()
-                && od->modifiedArgType().name() == cPyObjectT();
+                && od->modifiedArgType().name() == cPyObjectT;
             if (!typeReplacedByPyObject) {
                 if (usePyArgs)
                     pyArgName = pythonArgsAt(od->argPos());
@@ -3047,10 +3145,9 @@ void CppGenerator::writeSingleFunctionCall(TextStream &s,
             continue;
         auto argType = getArgumentType(func, argIdx);
         int argPos = argIdx - removedArgs;
-        QString argName = CPP_ARG(argPos);
         QString pyArgName = usePyArgs ? pythonArgsAt(argPos) : PYTHON_ARG;
         indirections[argIdx] =
-            writeArgumentConversion(s, argType, argName, pyArgName, errorReturn,
+            writeArgumentConversion(s, argType, CPP_ARG_N(argPos), pyArgName, errorReturn,
                                     func->implementingClass(), arg.defaultValueExpression(),
                                     func->isUserAdded());
     }
@@ -3155,10 +3252,10 @@ void CppGenerator::writeCppToPythonFunction(TextStream &s,
 QString CppGenerator::containerNativeToTargetTypeName(const ContainerTypeEntryCPtr &type)
 {
     QString result = type->targetLangApiName();
-    if (result != cPyObjectT()) {
+    if (result != cPyObjectT) {
         result = containerCpythonBaseName(type);
-        if (result == cPySequenceT())
-            result = cPyListT();
+        if (result == cPySequenceT)
+            result = cPyListT;
     }
     return result;
 }
@@ -3217,7 +3314,7 @@ void CppGenerator::writeIsPythonConvertibleToCppFunction(TextStream &s,
             << "return Shiboken::Conversions::nonePythonToCppNullPtr;\n" << outdent;
     } else {
         if (!condition.contains(u"pyIn"))
-            s << sbkUnusedVariableCast(u"pyIn");
+            s << sbkUnusedVariableCast("pyIn");
     }
     s << "if (" << condition << ")\n" << indent
         << "return " << pythonToCppFuncName << ";\n" << outdent
@@ -3474,7 +3571,7 @@ QString CppGenerator::argumentNameFromIndex(const ApiExtractorResult &api,
 {
     switch (argIndex) {
     case -1:
-        return u"self"_s;
+        return PYTHON_SELF_VAR;
     case 0:
         return PYTHON_RETURN_VAR;
     case 1: { // Single argument?
@@ -3624,7 +3721,7 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
                         const int idx = arg.argumentIndex() - removedArgs;
                         const auto deRef = argumentIndirections.at(i);
                         QString argName = AbstractMetaType::dereferencePrefix(deRef)
-                                          + CPP_ARG(idx);
+                                          + CPP_ARG_N(idx);
                         userArgs.append(argName);
                     }
                 }
@@ -3703,7 +3800,7 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
                 Q_ASSERT(owner == context.metaClass());
                 if (func->functionType() == AbstractMetaFunction::CopyConstructorFunction
                     && maxArgs == 1) {
-                    mc << "new ::" << context.effectiveClassName()
+                    mc << "new " << globalScopePrefix(context) << context.effectiveClassName()
                         << "(*" << CPP_ARG0 << ')';
                 } else {
                     const QString ctorCall = context.effectiveClassName() + u'('
@@ -3711,13 +3808,13 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
                     if (usePySideExtensions() && isQObject(owner)) {
                         s << "void *addr = PySide::nextQObjectMemoryAddr();\n";
                         uva << "if (addr != nullptr) {\n" << indent
-                            << "cptr = new (addr) ::" << ctorCall << ";\n"
-                            << "PySide::setNextQObjectMemoryAddr(nullptr);\n" << outdent
+                            << "cptr = new (addr) " << globalScopePrefix(context) << ctorCall
+                            << ";\nPySide::setNextQObjectMemoryAddr(nullptr);\n" << outdent
                             << "} else {\n" << indent
-                            << "cptr = new ::" << ctorCall << ";\n"
+                            << "cptr = new " << globalScopePrefix(context) << ctorCall << ";\n"
                             << outdent << "}\n";
                     } else {
-                        mc << "new ::" << ctorCall;
+                        mc << "new " << globalScopePrefix(context) << ctorCall;
                     }
                 }
             } else {
@@ -3731,7 +3828,7 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
                     const bool hasWrapper = shouldGenerateCppWrapper(ownerClass);
                     if (!avoidProtectedHack() || !func->isProtected() || !hasWrapper) {
                         if (func->isStatic()) {
-                            mc << "::" << methodCallClassName << "::";
+                            mc << m_gsp << methodCallClassName << "::";
                         } else {
                             const QString cppSelfVar = CPP_SELF_VAR;
                             const QString selfVarCast = func->ownerClass() == func->implementingClass()
@@ -3740,7 +3837,7 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
                                   + u" *>("_s + cppSelfVar + u')';
                             if (func->isConstant()) {
                                 if (avoidProtectedHack()) {
-                                    mc << "const_cast<const ::";
+                                    mc << "const_cast<const " << globalScopePrefix(context);
                                     if (ownerClass->cppWrapper().testFlag(AbstractMetaClass::CppProtectedHackWrapper)) {
                                         // PYSIDE-500: Need a special wrapper cast when inherited
                                         const QString selfWrapCast = ownerClass == func->implementingClass()
@@ -3755,7 +3852,7 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
                                         mc << " *>(" << selfVarCast << ")->";
                                     }
                                 } else {
-                                    mc << "const_cast<const ::" << methodCallClassName;
+                                    mc << "const_cast<const " << m_gsp << methodCallClassName;
                                     mc <<  " *>(" << selfVarCast << ")->";
                                 }
                             } else {
@@ -3777,8 +3874,7 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
 
                         if (!func->isAbstract())
                             mc << (func->isProtected() ? wrapperName(func->ownerClass()) :
-                                                         u"::"_s
-                                                         + methodCallClassName) << "::";
+                                                         m_gsp + methodCallClassName) << "::";
                         mc << func->originalName() << "_protected";
                     }
                 } else {
@@ -4033,7 +4129,7 @@ void CppGenerator::writeSpecialCastFunction(TextStream &s, const AbstractMetaCla
     QString className = metaClass->qualifiedCppName();
     s << "static void * " << cpythonSpecialCastFunctionName(metaClass)
         << "(void *obj, PyTypeObject *desiredType)\n{\n" << indent
-        << "auto me = reinterpret_cast< ::" << className << " *>(obj);\n";
+        << "auto me = reinterpret_cast< " << m_gsp << className << " *>(obj);\n";
     bool firstClass = true;
     const auto &allAncestors = metaClass->allTypeSystemAncestors();
     for (const auto &baseClass : allAncestors) {
@@ -4057,27 +4153,25 @@ void CppGenerator::writePrimitiveConverterInitialization(TextStream &s,
         << converter << " = Shiboken::Conversions::createConverter(";
     if (!type->hasTargetLangApiType())
         s << "nullptr";
-    else if (type->targetLangApiName() == cPyObjectT())
+    else if (type->targetLangApiName() == cPyObjectT)
         s << "&PyBaseObject_Type";
     else
         s << '&' << type->targetLangApiName() << "_Type";
     QString typeName = fixedCppTypeName(type);
     s << ", " << cppToPythonFunctionName(typeName, typeName) << ");\n"
-        << "Shiboken::Conversions::registerConverterName(" << converter << ", \""
-        << type->qualifiedCppName() << "\");\n";
+        << registerConverterName(type->qualifiedCppName(), converter);
     writeCustomConverterRegister(s, customConversion, converter);
 }
 
-static void registerEnumConverterScopes(TextStream &s, QString signature)
+static void registerConverterInScopes(TextStream &s, QStringView signature,
+                                      QAnyStringView varName = converterVar)
 {
     while (true) {
-        s << "Shiboken::Conversions::registerConverterName(converter, \""
-          << signature << "\");\n";
-        const auto qualifierPos = signature.indexOf(u"::");
-        if (qualifierPos != -1)
-            signature.remove(0, qualifierPos + 2);
-        else
+        s << registerConverterName(signature, varName);
+        const auto qualifierPos = signature.indexOf("::"_L1);
+        if (qualifierPos == -1)
             break;
+        signature = signature.sliced(qualifierPos + 2);
     }
 }
 
@@ -4104,27 +4198,30 @@ void CppGenerator::writeEnumConverterInitialization(TextStream &s, const Abstrac
     s << "Shiboken::Enum::setTypeConverter(" << enumPythonVar
         << ", converter);\n";
 
-    registerEnumConverterScopes(s, enumType->qualifiedCppName());
+    registerConverterInScopes(s, enumType->qualifiedCppName());
     if (auto flags = enumType->flags())
         s << "// Register converter for flag '" << flags->qualifiedCppName() << "'.\n"
-            << "Shiboken::Conversions::registerConverterName(converter, \""
-            << flags->name() << "\");\n";
+            << registerConverterName(flags->name()) // QMetaType
+            << registerConverterName(flags->originalName()); // Signals with flags
+
     s << outdent << "}\n";
 }
 
 QString CppGenerator::writeContainerConverterInitialization(TextStream &s,
-                                                            const AbstractMetaType &type)
+                                                            const AbstractMetaType &type,
+                                                            const ApiExtractorResult &api)
 {
-    QByteArray cppSignature = QMetaObject::normalizedSignature(type.cppSignature().toUtf8());
+    const auto cppSignature =
+        QString::fromUtf8(QMetaObject::normalizedSignature(type.cppSignature().toUtf8()));
     s << "// Register converter for type '" << cppSignature << "'.\n";
-    QString converter = converterObject(type);
+    const QString converter = converterObject(type);
     s << converter << " = Shiboken::Conversions::createConverter(";
 
     Q_ASSERT(type.typeEntry()->isContainer());
     const auto typeEntry = std::static_pointer_cast<const ContainerTypeEntry>(type.typeEntry());
 
     const QString targetTypeName = containerNativeToTargetTypeName(typeEntry);
-    if (targetTypeName == cPyObjectT()) {
+    if (targetTypeName == cPyObjectT) {
         s << "&PyBaseObject_Type";
     } else {
         s << '&' << targetTypeName << "_Type";
@@ -4133,24 +4230,39 @@ QString CppGenerator::writeContainerConverterInitialization(TextStream &s,
     const QString typeName = fixedCppTypeName(type);
     s << ", " << cppToPythonFunctionName(typeName, targetTypeName) << ");\n";
 
+    s << registerConverterName(cppSignature, converter);
+    if (usePySideExtensions() && cppSignature.startsWith("const "_L1)
+        && cppSignature.endsWith(u'&')) {
+        auto underlyingType = QStringView{cppSignature}.sliced(6, cppSignature.size() - 7);
+        s << registerConverterName(underlyingType, converter);
+    }
+
     for (const auto &conv : typeEntry->customConversion()->targetToNativeConversions()) {
         const QString &sourceTypeName = conv.sourceTypeName();
         QString toCpp = pythonToCppFunctionName(sourceTypeName, typeName);
         QString isConv = convertibleToCppFunctionName(sourceTypeName, typeName);
-        s << "Shiboken::Conversions::registerConverterName(" << converter
-            << ", \"" << cppSignature << "\");\n";
-        if (usePySideExtensions() && cppSignature.startsWith("const ")
-            && cppSignature.endsWith("&")) {
-            cppSignature.chop(1);
-            cppSignature.remove(0, sizeof("const ") / sizeof(char) - 1);
-            s << "Shiboken::Conversions::registerConverterName(" << converter
-                << ", \"" << cppSignature << "\");\n";
-        }
         writeAddPythonToCppConversion(s, converter, toCpp, isConv);
     }
+
+    auto typedefItPair = api.typedefTargetToName().equal_range(type.cppSignature());
+    if (typedefItPair.first != typedefItPair.second) {
+        auto *typeDb = TypeDatabase::instance();
+        s << "// Register converters for type aliases of " << cppSignature << "'.\n";
+        for (auto it = typedefItPair.first; it != typedefItPair.second; ++it) {
+            if (!typeDb->findType(it.value()))
+                s << registerConverterName(it.value(), converter);
+        }
+    }
+
     return converter;
 }
 
+QString CppGenerator::typeInitStruct(const TypeEntryCPtr &te)
+{
+    return cppApiVariableName(te->targetLangPackage()) + u'['
+        + getTypeIndexVariableName(te) + u']';
+}
+
 void CppGenerator::writeExtendedConverterInitialization(TextStream &s,
                                                         const TypeEntryCPtr &externalType,
                                                         const AbstractMetaClassCList &conversions)
@@ -4158,13 +4270,13 @@ void CppGenerator::writeExtendedConverterInitialization(TextStream &s,
     s << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName()
       << ".\n";
     for (const auto &sourceClass : conversions) {
-        const QString converterVar = cppApiVariableName(externalType->targetLangPackage()) + u'['
-            + getTypeIndexVariableName(externalType) + u']';
         QString sourceTypeName = fixedCppTypeName(sourceClass->typeEntry());
         QString targetTypeName = fixedCppTypeName(externalType);
         QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
         QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
-        writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+        if (!externalType->isPrimitive())
+            s << cpythonTypeNameExt(externalType) << ";\n";
+        writeAddPythonToCppConversion(s, typeInitStruct(externalType), toCpp, isConv);
     }
 }
 
@@ -4221,11 +4333,11 @@ bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClassCPtr &metaCla
 
 struct pyTypeSlotEntry
 {
-    explicit pyTypeSlotEntry(QStringView name, QStringView function) :
+    explicit pyTypeSlotEntry(QAnyStringView name, QAnyStringView function) :
         m_name(name), m_function(function) {}
 
-    QStringView m_name;
-    QStringView m_function;
+    QAnyStringView m_name;
+    QAnyStringView m_function;
 };
 
 TextStream &operator<<(TextStream &str, const pyTypeSlotEntry &e)
@@ -4247,7 +4359,6 @@ void CppGenerator::writeClassDefinition(TextStream &s,
     QString tp_hash;
     QString tp_call;
     const QString className = chopType(cpythonTypeName(metaClass));
-    QString baseClassName;
     AbstractMetaFunctionCList ctors;
     const auto &allCtors = metaClass->queryFunctions(FunctionQueryOption::AnyConstructor);
     for (const auto &f : allCtors) {
@@ -4257,9 +4368,6 @@ void CppGenerator::writeClassDefinition(TextStream &s,
         }
     }
 
-    if (!metaClass->baseClass())
-        baseClassName = u"SbkObject_TypeF()"_s;
-
     bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor();
 
     const bool isQApp = usePySideExtensions()
@@ -4353,7 +4461,7 @@ void CppGenerator::writeClassDefinition(TextStream &s,
     if (hasHashFunction(metaClass))
         tp_hash = u'&' + cpythonBaseName(metaClass) + u"_HashFunc"_s;
 
-    const auto callOp = metaClass->findFunction(u"operator()");
+    const auto callOp = metaClass->findFunction("operator()");
     if (callOp && !callOp->isModifiedRemoved())
         tp_call = u'&' + cpythonFunctionName(callOp);
 
@@ -4364,22 +4472,22 @@ void CppGenerator::writeClassDefinition(TextStream &s,
         << "{\n" << indent << "return " << typePtr << ";\n" << outdent
         << "}\n\nstatic PyType_Slot " << className << "_slots[] = {\n" << indent
         << "{Py_tp_base,        nullptr}, // inserted by introduceWrapperType\n"
-        << pyTypeSlotEntry(u"Py_tp_dealloc", tp_dealloc)
-      << pyTypeSlotEntry(u"Py_tp_repr", m_tpFuncs.value(REPR_FUNCTION))
-        << pyTypeSlotEntry(u"Py_tp_hash", tp_hash)
-        << pyTypeSlotEntry(u"Py_tp_call", tp_call)
-        << pyTypeSlotEntry(u"Py_tp_str", m_tpFuncs.value(u"__str__"_s))
-        << pyTypeSlotEntry(u"Py_tp_getattro", tp_getattro)
-        << pyTypeSlotEntry(u"Py_tp_setattro", tp_setattro)
-        << pyTypeSlotEntry(u"Py_tp_traverse", className + u"_traverse"_s)
-        << pyTypeSlotEntry(u"Py_tp_clear", className + u"_clear"_s)
-        << pyTypeSlotEntry(u"Py_tp_richcompare", tp_richcompare)
-        << pyTypeSlotEntry(u"Py_tp_iter", m_tpFuncs.value(u"__iter__"_s))
-        << pyTypeSlotEntry(u"Py_tp_iternext", m_tpFuncs.value(u"__next__"_s))
-        << pyTypeSlotEntry(u"Py_tp_methods", className + u"_methods"_s)
-        << pyTypeSlotEntry(u"Py_tp_getset", tp_getset)
-        << pyTypeSlotEntry(u"Py_tp_init", tp_init)
-        << pyTypeSlotEntry(u"Py_tp_new", tp_new);
+        << pyTypeSlotEntry("Py_tp_dealloc", tp_dealloc)
+      << pyTypeSlotEntry("Py_tp_repr", m_tpFuncs.value(REPR_FUNCTION))
+        << pyTypeSlotEntry("Py_tp_hash", tp_hash)
+        << pyTypeSlotEntry("Py_tp_call", tp_call)
+        << pyTypeSlotEntry("Py_tp_str", m_tpFuncs.value(u"__str__"_s))
+        << pyTypeSlotEntry("Py_tp_getattro", tp_getattro)
+        << pyTypeSlotEntry("Py_tp_setattro", tp_setattro)
+        << pyTypeSlotEntry("Py_tp_traverse", className + u"_traverse"_s)
+        << pyTypeSlotEntry("Py_tp_clear", className + u"_clear"_s)
+        << pyTypeSlotEntry("Py_tp_richcompare", tp_richcompare)
+        << pyTypeSlotEntry("Py_tp_iter", m_tpFuncs.value(u"__iter__"_s))
+        << pyTypeSlotEntry("Py_tp_iternext", m_tpFuncs.value(u"__next__"_s))
+        << pyTypeSlotEntry("Py_tp_methods", className + u"_methods"_s)
+        << pyTypeSlotEntry("Py_tp_getset", tp_getset)
+        << pyTypeSlotEntry("Py_tp_init", tp_init)
+        << pyTypeSlotEntry("Py_tp_new", tp_new);
     if (supportsSequenceProtocol(metaClass)) {
         s << "// type supports sequence protocol\n";
         writeTypeAsSequenceDefinition(s, metaClass);
@@ -4592,7 +4700,9 @@ void CppGenerator::writeTpTraverseFunction(TextStream &s, const AbstractMetaClas
     QString baseName = cpythonBaseName(metaClass);
     s << "static int " << baseName
         << "_traverse(PyObject *self, visitproc visit, void *arg)\n{\n" << indent
-        << "return SbkObject_TypeF()->tp_traverse(self, visit, arg);\n"
+        << "auto traverseProc = "
+        << pyTypeGetSlot("traverseproc", sbkObjectTypeF, "Py_tp_traverse") << ";\n"
+        << "return traverseProc(self, visit, arg);\n"
         << outdent << "}\n";
 }
 
@@ -4600,7 +4710,9 @@ void CppGenerator::writeTpClearFunction(TextStream &s, const AbstractMetaClassCP
 {
     QString baseName = cpythonBaseName(metaClass);
     s << "static int " << baseName << "_clear(PyObject *self)\n{\n" << indent
-       << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_clear(self);\n"
+       << "auto clearProc = "
+       << pyTypeGetSlot("inquiry", sbkObjectTypeF, "Py_tp_clear") << ";\n"
+       << "return clearProc(self);\n"
        << outdent << "}\n";
 }
 
@@ -4736,7 +4848,7 @@ void CppGenerator::writeGetterFunction(TextStream &s,
 {
     writeGetterFunctionStart(s, cpythonGetterFunctionName(property, context.metaClass()));
     writeCppSelfDefinition(s, context);
-    const QString value = QStringLiteral("value");
+    const QString value = "value"_L1;
     s << "auto " << value << " = " << CPP_SELF_VAR << "->" << property.read() << "();\n"
         << "auto *pyResult = ";
     writeToPythonConversion(s, property.type(), context.metaClass(), value);
@@ -4984,6 +5096,17 @@ QList<PyMethodDefEntry>
     return result;
 }
 
+QString CppGenerator::pythonSignature(const AbstractMetaType &type) const
+{
+    if (type.isSmartPointer() && !type.instantiations().isEmpty()) {
+        const auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(type.typeEntry());
+        const auto instantiationTe = type.instantiations().constFirst().typeEntry();
+        if (auto opt = api().findSmartPointerInstantiation(ste, instantiationTe))
+            return opt->specialized->typeEntry()->qualifiedTargetLangName();
+    }
+    return type.pythonSignature();
+}
+
 // Format the type signature of a function parameter
 QString CppGenerator::signatureParameter(const AbstractMetaArgument &arg) const
 {
@@ -4995,17 +5118,22 @@ QString CppGenerator::signatureParameter(const AbstractMetaArgument &arg) const
         metaType = *viewOn;
     s << arg.name() << ':';
 
-    QStringList signatures(metaType.pythonSignature());
+    QStringList signatures(pythonSignature(metaType));
 
     // Implicit conversions (C++): Check for converting constructors
     // "QColor(Qt::GlobalColor)" or conversion operators
     const AbstractMetaFunctionCList conversions =
         api().implicitConversions(metaType);
     for (const auto &f : conversions) {
-        if (f->isConstructor() && !f->arguments().isEmpty())
-            signatures << f->arguments().constFirst().type().pythonSignature();
-        else if (f->isConversionOperator())
+        if (f->isConstructor() && !f->arguments().isEmpty()) {
+            // PYSIDE-2712: modified types from converting constructors are not always correct
+            // candidates if they are modified by the type system reference
+            if (!f->arguments().constFirst().isTypeModified()) {
+                signatures << pythonSignature(f->arguments().constFirst().type());
+            }
+        } else if (f->isConversionOperator()) {
             signatures << f->ownerClass()->fullName();
+        }
     }
 
     const qsizetype size = signatures.size();
@@ -5035,7 +5163,7 @@ void CppGenerator::writeSignatureInfo(TextStream &s, const OverloadData &overloa
         // PYSIDE-1328: `self`-ness cannot be computed in Python because there are mixed cases.
         // Toplevel functions like `PySide6.QtCore.QEnum` are always self-less.
         if (!(f->isStatic()) && f->ownerClass())
-            args << u"self"_s;
+            args << PYTHON_SELF_VAR;
         const auto &arguments = f->arguments();
         for (qsizetype i = 0, size = arguments.size(); i < size; ++i) {
             const auto n = i + 1;
@@ -5062,7 +5190,7 @@ void CppGenerator::writeSignatureInfo(TextStream &s, const OverloadData &overloa
 
         QString returnType = f->pyiTypeReplaced(0); // pyi or modified type
         if (returnType.isEmpty() && !f->isVoid())
-            returnType = f->type().pythonSignature();
+            returnType = pythonSignature(f->type());
         if (!returnType.isEmpty())
             s << "->" << returnType;
 
@@ -5090,7 +5218,7 @@ void CppGenerator::writeEnumsInitialization(TextStream &s, AbstractMetaEnumList
         etypeUsed |= writeEnumInitialization(s, cppEnum);
     }
     if (preambleWritten && !etypeUsed)
-        s << sbkUnusedVariableCast(u"EType");
+        s << sbkUnusedVariableCast("EType");
 }
 
 static qsizetype maxLineLength(const QStringList &list)
@@ -5214,7 +5342,7 @@ bool CppGenerator::writeEnumInitialization(TextStream &s, const AbstractMetaEnum
 
     bool etypeUsed = false;
 
-    QString enumVarTypeObj = cpythonTypeNameExt(enumTypeEntry);
+    QString enumVarTypeObj = cpythonTypeNameExtSet(enumTypeEntry);
     if (!cppEnum.isAnonymous()) {
         int packageLevel = packageName().count(u'.') + 1;
         s << "EType = Shiboken::Enum::"
@@ -5228,7 +5356,7 @@ bool CppGenerator::writeEnumInitialization(TextStream &s, const AbstractMetaEnum
 
     if (cppEnum.typeEntry()->flags()) {
         s << "// PYSIDE-1735: Mapping the flags class to the same enum class.\n"
-            << cpythonTypeNameExt(cppEnum.typeEntry()->flags()) << " =\n"
+            << cpythonTypeNameExtSet(cppEnum.typeEntry()->flags()) << " =\n"
             << indent << "EType;\n" << outdent;
     }
     writeEnumConverterInitialization(s, cppEnum);
@@ -5263,7 +5391,7 @@ void CppGenerator::writeSignalInitialization(TextStream &s, const AbstractMetaCl
         }
     }
 
-    s << "PySide::Signal::registerSignals(pyType, &::"
+    s << "PySide::Signal::registerSignals(pyType, &" << m_gsp
        << metaClass->qualifiedCppName() << "::staticMetaObject);\n";
 }
 
@@ -5328,6 +5456,61 @@ QString CppGenerator::destructorClassName(const AbstractMetaClassCPtr &metaClass
     return metaClass->qualifiedCppName();
 }
 
+// Return the base type entries for introduceWrapperType()
+static ComplexTypeEntryCList pyBaseTypeEntries(const AbstractMetaClassCPtr &metaClass)
+{
+    ComplexTypeEntryCList result;
+    if (metaClass->isNamespace()) {
+        if (auto extended = metaClass->extendedNamespace())
+            result.append(extended->typeEntry());
+        return result;
+    }
+
+    const auto &baseClasses = metaClass->typeSystemBaseClasses();
+    for (auto base : baseClasses) {
+        for (; base != nullptr; base = base->baseClass()) { // Find a type that is not disabled.
+            const auto ct = base->typeEntry()->codeGeneration();
+            if (ct == TypeEntry::GenerateCode || ct == TypeEntry::GenerateForSubclass)
+                break;
+        }
+        result.append(base->typeEntry());
+    }
+    return result;
+}
+
+// Return the base type strings for introduceWrapperType()
+QStringList CppGenerator::pyBaseTypes(const AbstractMetaClassCPtr &metaClass)
+{
+    const auto &baseEntries = pyBaseTypeEntries(metaClass);
+    QStringList result;
+    for (const auto &baseEntry : baseEntries)
+        result.append("reinterpret_cast<PyObject *>("_L1 + cpythonTypeNameExt(baseEntry) + u')');
+    if (result.isEmpty()) // no base classes -> SbkObjectType.
+        result.append(sbkObjectTypeF);
+    return result;
+}
+
+void CppGenerator::writeInitInheritance(TextStream &s) const
+{
+    s << "static void " << initInheritanceFunction << "()\n{\n" << indent
+        << "auto &bm = Shiboken::BindingManager::instance();\n"
+        << sbkUnusedVariableCast("bm");
+    for (const auto &cls : api().classes()){
+        auto te = cls->typeEntry();
+        if (shouldGenerate(te)) {
+            const auto &baseEntries = pyBaseTypeEntries(cls);
+            if (!baseEntries.isEmpty()) {
+                const QString childTypeInitStruct = typeInitStruct(cls->typeEntry());
+                for (const auto &baseEntry : baseEntries) {
+                    s << "bm.addClassInheritance(&" << typeInitStruct(baseEntry) << ",\n"
+                      << Pad(' ', 23) << '&' << childTypeInitStruct << ");\n";
+                }
+            }
+        }
+    }
+    s << outdent << "}\n\n";
+}
+
 void CppGenerator::writeClassRegister(TextStream &s,
                                       const AbstractMetaClassCPtr &metaClass,
                                       const GeneratorContext &classContext,
@@ -5343,23 +5526,26 @@ void CppGenerator::writeClassRegister(TextStream &s,
 
     // PYSIDE-510: Create a signatures string for the introspection feature.
     writeSignatureStrings(s, signatures, initFunctionName, "functions");
-    s << "void init_" << initFunctionName;
-    s << "(PyObject *" << enclosingObjectVariable << ")\n{\n" << indent;
+    s << "PyTypeObject *init_" << initFunctionName
+        << "(PyObject *" << enclosingObjectVariable << ")\n{\n" << indent;
+
+    const QString globalTypeVarExpr = !classContext.forSmartPointer()
+                                      ? cpythonTypeNameExtSet(classTypeEntry)
+                                      : cpythonTypeNameExtSet(classContext.preciseType());
+    s << "if (" << globalTypeVarExpr << " != nullptr)\n" << indent
+        << "return " << globalTypeVarExpr << ";\n\n" << outdent;
 
     // Multiple inheritance
     QString pyTypeBasesVariable = chopType(pyTypeName) + u"_Type_bases"_s;
-    const auto &baseClasses = metaClass->typeSystemBaseClasses();
-    if (metaClass->baseClassNames().size() > 1) {
-        s << "PyObject *" << pyTypeBasesVariable
-            << " = PyTuple_Pack(" << baseClasses.size() << ',' << '\n' << indent;
-        for (qsizetype i = 0, size = baseClasses.size(); i < size; ++i) {
-            if (i)
-                s << ",\n";
-            s << "reinterpret_cast<PyObject *>("
-                << cpythonTypeNameExt(baseClasses.at(i)->typeEntry()) << ')';
-        }
-        s << ");\n\n" << outdent;
+    const QStringList pyBases = pyBaseTypes(metaClass);
+    s << "Shiboken::AutoDecRef " << pyTypeBasesVariable << "(PyTuple_Pack("
+        << pyBases.size() << ",\n" << indent;
+    for (qsizetype i = 0, size = pyBases.size(); i < size; ++i) {
+        if (i)
+            s << ",\n";
+        s << pyBases.at(i);
     }
+    s << "));\n\n" << outdent;
 
     // Create type and insert it in the module or enclosing class.
     const QString typePtr = u"_"_s + chopType(pyTypeName)
@@ -5391,29 +5577,11 @@ void CppGenerator::writeClassRegister(TextStream &s,
     if (dtorClassName.isEmpty())
         s << "nullptr,\n";
     else
-        s << "&Shiboken::callCppDestructor< ::" << dtorClassName << " >,\n";
-
-    // 6:baseType: Find a type that is not disabled.
-    auto base = metaClass->isNamespace()
-        ? metaClass->extendedNamespace() : metaClass->baseClass();
-    if (!metaClass->isNamespace()) {
-        for (; base != nullptr; base = base->baseClass()) {
-            const auto ct = base->typeEntry()->codeGeneration();
-            if (ct == TypeEntry::GenerateCode || ct == TypeEntry::GenerateForSubclass)
-                break;
-        }
-    }
-    if (base) {
-        s << cpythonTypeNameExt(base->typeEntry()) << ",\n";
-    } else {
-        s << "nullptr,\n";
-    }
+        s << "&Shiboken::callCppDestructor< " << globalScopePrefix(classContext)
+            << dtorClassName << " >,\n";
 
     // 7:baseTypes
-    if (metaClass->baseClassNames().size() > 1)
-        s << pyTypeBasesVariable << ',' << '\n';
-    else
-        s << "0,\n";
+    s << pyTypeBasesVariable << ".object()," << '\n';
 
     // 8:wrapperflags
     QByteArrayList wrapperFlags;
@@ -5421,6 +5589,8 @@ void CppGenerator::writeClassRegister(TextStream &s,
         wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::InnerClass"));
     if (metaClass->deleteInMainThread())
         wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::DeleteInMainThread"));
+    if (classTypeEntry->isValue())
+        wrapperFlags.append("Shiboken::ObjectType::WrapperFlags::Value"_ba);
     if (wrapperFlags.isEmpty())
         s << '0';
     else
@@ -5433,11 +5603,7 @@ void CppGenerator::writeClassRegister(TextStream &s,
     if (usePySideExtensions() && !classContext.forSmartPointer())
         s << "SbkObjectType_SetPropertyStrings(pyType, "
                     << chopType(pyTypeName) << "_PropertyStrings);\n";
-
-    if (!classContext.forSmartPointer())
-        s << cpythonTypeNameExt(classTypeEntry) << " = pyType;\n\n";
-    else
-        s << cpythonTypeNameExt(classContext.preciseType()) << " = pyType;\n\n";
+    s << globalTypeVarExpr << " = pyType;\n\n";
 
     // Register conversions for the type.
     writeConverterRegister(s, metaClass, classContext);
@@ -5503,22 +5669,38 @@ void CppGenerator::writeClassRegister(TextStream &s,
 
     if (usePySideExtensions() && isQObject(metaClass)) {
         s << "Shiboken::ObjectType::setSubTypeInitHook(pyType, &PySide::initQObjectSubType);\n"
-            << "PySide::initDynamicMetaObject(pyType, &::"
+          << "PySide::initDynamicMetaObject(pyType, &" << m_gsp
             << metaClass->qualifiedCppName() << "::staticMetaObject, sizeof("
             << (shouldGenerateCppWrapper(metaClass)
                 ? wrapperName(metaClass) : getFullTypeName(metaClass))
             << "));\n";
     }
 
-    s << outdent << "}\n";
+    s << "\nreturn pyType;\n" << outdent << "}\n";
 }
 
 void CppGenerator::writeStaticFieldInitialization(TextStream &s,
                                                   const AbstractMetaClassCPtr &metaClass)
 {
-    s << "\nvoid " << getSimpleClassStaticFieldsInitFunctionName(metaClass)
-        << "()\n{\n" << indent << "Shiboken::AutoDecRef dict(PepType_GetDict(reinterpret_cast<PyTypeObject *>("
-        << cpythonTypeName(metaClass) << ")));\n";
+    // cpythonTypeName == "Sbk_QRhiShaderResourceBinding_Data_TypeF"
+    QString name = cpythonTypeName(metaClass);
+    const auto parts = QStringView{name}.split(u'_', Qt::SkipEmptyParts);
+    if (parts.size() < 4) {
+        s << "\nPyTypeObject *" << getSimpleClassStaticFieldsInitFunctionName(metaClass)
+            << "(PyObject *module)\n{\n" << indent
+            << "auto *obType = PyObject_GetAttrString(module, \"" << metaClass->name() << "\");\n"
+            << "auto *type = reinterpret_cast<PyTypeObject *>(obType);\n"
+            << "Shiboken::AutoDecRef dict(PepType_GetDict(type));\n";
+    } else {
+        s << "\nPyTypeObject *" << getSimpleClassStaticFieldsInitFunctionName(metaClass)
+            << "(PyObject *module)\n{\n" << indent
+            << "auto *obContainerType = PyObject_GetAttrString(module, \""
+            << parts.at(1) << "\");\n"
+            << "auto *obType = PyObject_GetAttrString(obContainerType, \""
+            << parts.at(2) << "\");\n"
+            << "auto *type = reinterpret_cast<PyTypeObject *>(obType);\n"
+            << "Shiboken::AutoDecRef dict(PepType_GetDict(type));\n";
+    }
     for (const AbstractMetaField &field : metaClass->fields()) {
         if (field.isStatic()) {
             s << "PyDict_SetItemString(dict, \"" << field.name()
@@ -5527,7 +5709,7 @@ void CppGenerator::writeStaticFieldInitialization(TextStream &s,
             s << ");\n";
         }
     }
-    s << '\n' << outdent << "}\n";
+    s << "return type;\n" << outdent << "}\n";
 }
 
 enum class QtRegisterMetaType
@@ -5606,18 +5788,18 @@ void CppGenerator::writeInitQtMetaTypeFunctionBody(TextStream &s, const Generato
     case QtRegisterMetaType::None:
         break;
     case QtRegisterMetaType::Pointer:
-        s << "qRegisterMetaType< ::" << className << " *>();\n";
+        s << "qRegisterMetaType< " << m_gsp << className << " *>();\n";
         break;
     case QtRegisterMetaType::Value:
         for (const QString &name : std::as_const(nameVariants))
-            s << "qRegisterMetaType< ::" << className << " >(\"" << name << "\");\n";
+            s << "qRegisterMetaType< " << m_gsp << className << " >(\"" << name << "\");\n";
         break;
     }
 
     for (const AbstractMetaEnum &metaEnum : metaClass->enums()) {
         if (!metaEnum.isPrivate() && !metaEnum.isAnonymous()) {
             for (const QString &name : std::as_const(nameVariants)) {
-                s << "qRegisterMetaType< ::"
+                s << "qRegisterMetaType< " << m_gsp
                     << metaEnum.typeEntry()->qualifiedCppName() << " >(\""
                     << name << "::" << metaEnum.name() << "\");\n";
             }
@@ -5625,6 +5807,24 @@ void CppGenerator::writeInitQtMetaTypeFunctionBody(TextStream &s, const Generato
     }
 }
 
+void CppGenerator::replacePolymorphicIdPlaceHolders(const AbstractMetaClassCPtr &metaClass,
+                                                    QString *id)
+{
+    if (id->contains("%1"_L1)) {
+        QString replacement = " reinterpret_cast< "_L1 + m_gsp + metaClass->qualifiedCppName()
+                              + " *>(cptr)"_L1;
+        id->replace("%1"_L1, replacement);
+    }
+    if (id->contains("%B"_L1)) {
+        auto baseClass = metaClass;
+        while (!baseClass->typeEntry()->isPolymorphicBase() && baseClass->baseClass())
+            baseClass = baseClass->baseClass();
+        QString replacement = " reinterpret_cast< "_L1 + m_gsp + baseClass->qualifiedCppName()
+                              + " *>(cptr)"_L1;
+        id->replace("%B"_L1, replacement);
+    }
+}
+
 void CppGenerator::writeTypeDiscoveryFunction(TextStream &s,
                                               const AbstractMetaClassCPtr &metaClass)
 {
@@ -5632,15 +5832,12 @@ void CppGenerator::writeTypeDiscoveryFunction(TextStream &s,
 
     s << "static void *" << cpythonBaseName(metaClass)
         << "_typeDiscovery(void *cptr, PyTypeObject *instanceType)\n{\n" << indent
-        << sbkUnusedVariableCast(u"cptr"_s)
-        << sbkUnusedVariableCast(u"instanceType");
+        << sbkUnusedVariableCast("cptr")
+        << sbkUnusedVariableCast("instanceType");
 
     if (!polymorphicExpr.isEmpty()) {
-        polymorphicExpr = polymorphicExpr.replace(u"%1"_s,
-                                                  u" reinterpret_cast< ::"_s
-                                                  + metaClass->qualifiedCppName()
-                                                  + u" *>(cptr)"_s);
-        s << " if (" << polymorphicExpr << ")\n" << indent
+        replacePolymorphicIdPlaceHolders(metaClass, &polymorphicExpr);
+        s << "if (" << polymorphicExpr << ")\n" << indent
             << "return cptr;\n" << outdent;
     } else if (metaClass->isPolymorphic()) {
         const auto &ancestors = metaClass->allTypeSystemAncestors();
@@ -5648,7 +5845,7 @@ void CppGenerator::writeTypeDiscoveryFunction(TextStream &s,
             if (ancestor->baseClass())
                 continue;
             if (ancestor->isPolymorphic()) {
-                s << "if (instanceType == Shiboken::SbkType< ::"
+                s << "if (instanceType == Shiboken::SbkType< " << m_gsp
                     << ancestor->qualifiedCppName() << " >())\n" << indent
                     << "return dynamic_cast< " << getFullTypeName(metaClass)
                     << " *>(reinterpret_cast< "<< getFullTypeName(ancestor)
@@ -5697,7 +5894,7 @@ void CppGenerator::writeSetattroFunction(TextStream &s, AttroCheck attroCheck,
     if (attroCheck.testFlag(AttroCheckFlag::SetattroMethodOverride)
             && context.useWrapper()) {
         s << "if (value != nullptr && PyCallable_Check(value) != 0) {\n" << indent
-            << "auto plain_inst = " << cpythonWrapperCPtr(metaClass, u"self"_s) << ";\n"
+            << "auto plain_inst = " << cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR) << ";\n"
             << "auto *inst = dynamic_cast<" << context.wrapperName() << " *>(plain_inst);\n"
             << "if (inst != nullptr)\n" << indent
             << "inst->resetPyMethodCache();\n" << outdent << outdent
@@ -5716,7 +5913,7 @@ void CppGenerator::writeSetattroFunction(TextStream &s, AttroCheck attroCheck,
         Q_ASSERT(func);
         s << "{\n" << indent
             << "auto " << CPP_SELF_VAR << " = "
-            << cpythonWrapperCPtr(metaClass, u"self"_s) << ";\n";
+            << cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR) << ";\n";
         writeClassCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionAny,
                             TypeSystem::TargetLangCode, context);
         s << outdent << "}\n";
@@ -5735,10 +5932,10 @@ QString CppGenerator::qObjectGetAttroFunction() const
 {
     static QString result;
     if (result.isEmpty()) {
-        auto qobjectClass = AbstractMetaClass::findClass(api().classes(), qObjectT());
+        auto qobjectClass = AbstractMetaClass::findClass(api().classes(), qObjectT);
         Q_ASSERT(qobjectClass);
         result = u"PySide::getHiddenDataFromQObject("_s
-                 + cpythonWrapperCPtr(qobjectClass, u"self"_s)
+                 + cpythonWrapperCPtr(qobjectClass, PYTHON_SELF_VAR)
                  + u", self, name)"_s;
     }
     return result;
@@ -5770,9 +5967,11 @@ void CppGenerator::writeGetattroFunction(TextStream &s, AttroCheck attroCheck,
             << "Shiboken::AutoDecRef tpDict(PepType_GetDict(Py_TYPE(self)));\n"
             << "if (auto *meth = PyDict_GetItem(tpDict.object(), tmp)) {\n" << indent;
         // PYSIDE-1523: PyFunction_Check is not accepting compiled functions.
-        s << "if (std::strcmp(Py_TYPE(meth)->tp_name, \"compiled_function\") == 0)\n" << indent
-            << "return Py_TYPE(meth)->tp_descr_get(meth, self, nullptr);\n" << outdent
-            << "return PyFunction_Check(meth) ? PyMethod_New(meth, self)\n"
+        s << "if (std::strcmp(Py_TYPE(meth)->tp_name, \"compiled_function\") == 0) {\n" << indent
+            << "auto descrGetFunc = "
+            << pyTypeGetSlot("descrgetfunc", "Py_TYPE(meth)", "Py_tp_descr_get") << ";\n"
+            << "return descrGetFunc(meth, self, nullptr);\n" << outdent
+            << "}\nreturn PyFunction_Check(meth) ? PyMethod_New(meth, self)\n"
             << "                              : " << getattrFunc << ";\n" << outdent
             << "}\n" << outdent << "}\n";
 
@@ -5798,7 +5997,7 @@ void CppGenerator::writeGetattroFunction(TextStream &s, AttroCheck attroCheck,
         Q_ASSERT(func);
         s << "{\n" << indent
             << "auto " << CPP_SELF_VAR << " = "
-            << cpythonWrapperCPtr(metaClass, u"self"_s) << ";\n";
+            << cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR) << ";\n";
         writeClassCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionAny,
                             TypeSystem::TargetLangCode, context);
         s << outdent << "}\n";
@@ -5847,21 +6046,50 @@ void CppGenerator::writeNbBoolFunction(const GeneratorContext &context,
 // function.
 void CppGenerator::writeInitFunc(TextStream &declStr, TextStream &callStr,
                                  const QString &initFunctionName,
-                                 const TypeEntryCPtr &enclosingEntry)
+                                 const TypeEntryCPtr &enclosingEntry,
+                                 const QString &pythonName, bool lazy)
 {
-    const bool hasParent =
-        enclosingEntry && enclosingEntry->type() != TypeEntry::TypeSystemType;
-    declStr << "void init_" << initFunctionName << "(PyObject *"
+    const QString functionName = "init_"_L1 + initFunctionName;
+    const bool hasParent = enclosingEntry && enclosingEntry->type() != TypeEntry::TypeSystemType;
+    declStr << "PyTypeObject *" << functionName << "(PyObject *"
         << (hasParent ? "enclosingClass" : "module") << ");\n";
-    callStr << "init_" << initFunctionName;
-    if (hasParent) {
-        callStr << "(reinterpret_cast<PyObject *>("
-        << cpythonTypeNameExt(enclosingEntry) << "));\n";
+
+    if (!lazy) {
+        const QString enclosing = hasParent
+            ? "reinterpret_cast<PyObject *>("_L1 + cpythonTypeNameExt(enclosingEntry) + u')'
+            : "module"_L1;
+        callStr << functionName << '(' << enclosing << ");\n";
+    } else if (hasParent) {
+        const QString &enclosingName = enclosingEntry->name();
+        const auto parts = QStringView{enclosingName}.split(u"::", Qt::SkipEmptyParts);
+        callStr << "Shiboken::Module::AddTypeCreationFunction("
+            << "module, \"" << pythonName << "\", " << functionName << ", \"";
+        for (qsizetype i = 0; i < parts.size(); ++i) {
+            if (i > 0)
+               callStr << "\", \"";
+            callStr << parts.at(i);
+        }
+        callStr << "\");\n";
     } else {
-        callStr << "(module);\n";
+        callStr << "Shiboken::Module::AddTypeCreationFunction("
+            << "module, \"" << pythonName << "\", "
+            << "init_" << initFunctionName << ");\n";
     }
 }
 
+static void writeSubModuleHandling(TextStream &s, const QString &moduleName,
+                                   const QString &subModuleOf)
+{
+    s << "{\n" << indent
+        << "Shiboken::AutoDecRef parentModule(Shiboken::Module::import(\""
+        << subModuleOf << "\"));\n"
+        << "if (parentModule.isNull())\n" << indent
+        << "return nullptr;\n" << outdent
+        << "if (PyModule_AddObject(parentModule.object(), \"" << moduleName
+        << "\", module) < 0)\n"
+        << indent << "return nullptr;\n" << outdent << outdent << "}\n";
+}
+
 bool CppGenerator::finishGeneration()
 {
     //Generate CPython wrapper file
@@ -5904,10 +6132,10 @@ bool CppGenerator::finishGeneration()
             }
             writeInitFunc(s_classInitDecl, s_classPythonDefines,
                           getSimpleClassInitFunctionName(cls),
-                          targetLangEnclosingEntry(te));
+                          targetLangEnclosingEntry(te), cls->name());
             if (cls->hasStaticFields()) {
-                s_classInitDecl << "void "
-                    << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n";
+                s_classInitDecl << "PyTypeObject *"
+                    << getSimpleClassStaticFieldsInitFunctionName(cls) << "(PyObject *module);\n";
                 classesWithStaticFields.append(cls);
             }
             if (hasConfigCondition) {
@@ -5921,13 +6149,11 @@ bool CppGenerator::finishGeneration()
     for (const auto &smp : api().instantiatedSmartPointers()) {
         GeneratorContext context = contextForSmartPointer(smp.specialized, smp.type);
         const auto enclosingClass = context.metaClass()->enclosingClass();
-        auto enclosingTypeEntry = enclosingClass
-            ? enclosingClass->typeEntry()
-            : targetLangEnclosingEntry(smp.type.typeEntry());
+        auto enclosingTypeEntry = targetLangEnclosingEntry(smp.specialized->typeEntry());
 
         writeInitFunc(s_classInitDecl, s_classPythonDefines,
                       getInitFunctionName(context),
-                      enclosingTypeEntry);
+                      enclosingTypeEntry, smp.type.name());
         includes.insert(smp.type.instantiations().constFirst().typeEntry()->include());
     }
 
@@ -6010,12 +6236,15 @@ bool CppGenerator::finishGeneration()
         s << '\n';
     }
 
+    // FIXME PYSIDE-7: Remove backwards compatible structure
     s << "// Current module's type array.\n"
-       << "PyTypeObject **" << cppApiVariableName() << " = nullptr;\n"
+       << "Shiboken::Module::TypeInitStruct *" << cppApiVariableName() << " = nullptr;\n"
+       << "// Backwards compatible structure with identical indexing.\n"
+       << "PyTypeObject **" << cppApiVariableNameOld() << " = nullptr;\n"
        << "// Current module's PyObject pointer.\n"
        << "PyObject *" << pythonModuleObjectName() << " = nullptr;\n"
        << "// Current module's converter array.\n"
-       << "SbkConverter **" << convertersVariableName() << " = nullptr;\n";
+       << "SbkConverter **" << convertersVariableName() << " = nullptr;\n\n";
 
     const CodeSnipList snips = moduleEntry->codeSnips();
 
@@ -6024,14 +6253,17 @@ bool CppGenerator::finishGeneration()
 
     // cleanup staticMetaObject attribute
     if (usePySideExtensions()) {
+        QString iType = cppApiVariableName() + "[i].type"_L1;
+        QString iName = cppApiVariableName() + "[i].fullName"_L1;
+
         s << "void cleanTypesAttributes() {\n" << indent
             << "static PyObject *attrName = Shiboken::PyName::qtStaticMetaObject();\n"
-            << "for (int i = 0, imax = SBK_" << moduleName()
-            << "_IDX_COUNT; i < imax; i++) {\n" << indent
-            << "PyObject *pyType = reinterpret_cast<PyObject *>(" << cppApiVariableName() << "[i]);\n"
-            << "if (pyType && PyObject_HasAttr(pyType, attrName))\n" << indent
+            << "const int imax = SBK_" << moduleName() << "_IDX_COUNT;\n"
+            << "for (int i = 0; i < imax && " << iName << " != nullptr; ++i) {\n" << indent
+            << "auto *pyType = reinterpret_cast<PyObject *>(" << iType << ");\n"
+            << "if (pyType != nullptr && PyObject_HasAttr(pyType, attrName))\n" << indent
             << "PyObject_SetAttr(pyType, attrName, Py_None);\n" << outdent
-            << outdent << "}\n" << outdent << "}\n";
+            << outdent << "}\n" << outdent << "}\n\n";
     }
 
     s << "// Global functions "
@@ -6067,7 +6299,7 @@ bool CppGenerator::finishGeneration()
     if (!requiredModules.isEmpty())
         s << "// Required modules' type and converter arrays.\n";
     for (const QString &requiredModule : requiredModules) {
-        s << "PyTypeObject **" << cppApiVariableName(requiredModule) << ";\n"
+        s << "Shiboken::Module::TypeInitStruct *" << cppApiVariableName(requiredModule) << ";\n"
             << "SbkConverter **" << convertersVariableName(requiredModule) << ";\n";
     }
 
@@ -6141,6 +6373,8 @@ bool CppGenerator::finishGeneration()
     // PYSIDE-510: Create a signatures string for the introspection feature.
     writeSignatureStrings(s, signatureStream.toString(), moduleName(), "global functions");
 
+    writeInitInheritance(s);
+
     // Write module init function
     const QString globalModuleVar = pythonModuleObjectName();
     s << "extern \"C\" LIBSHIBOKEN_EXPORT PyObject *PyInit_"
@@ -6167,9 +6401,30 @@ bool CppGenerator::finishGeneration()
 
     int maxTypeIndex = getMaxTypeIndex() + api().instantiatedSmartPointers().size();
     if (maxTypeIndex) {
-        s << "// Create an array of wrapper types for the current module.\n"
-           << "static PyTypeObject *cppApi[SBK_" << moduleName() << "_IDX_COUNT];\n"
-           << cppApiVariableName() << " = cppApi;\n\n";
+        s << "// Create an array of wrapper types/names for the current module.\n"
+            << "static Shiboken::Module::TypeInitStruct cppApi[] = {\n" << indent;
+
+        // Windows did not like an array of QString.
+        QStringList typeNames;
+        for (int idx = 0; idx < maxTypeIndex; ++idx)
+            typeNames.append("+++ unknown entry #"_L1 + QString::number(idx)
+                             + " in "_L1 + moduleName());
+
+        collectFullTypeNamesArray(typeNames);
+
+        for (auto typeName : typeNames)
+            s << "{nullptr, \"" << typeName << "\"},\n";
+
+        s << "{nullptr, nullptr}\n" << outdent << "};\n"
+            << "// The new global structure consisting of (type, name) pairs.\n"
+            << cppApiVariableName() << " = cppApi;\n";
+        if (usePySideExtensions())
+            s << "QT_WARNING_PUSH\nQT_WARNING_DISABLE_DEPRECATED\n";
+        s << "// The backward compatible alias with upper case indexes.\n"
+            << cppApiVariableNameOld() << " = reinterpret_cast<PyTypeObject **>(cppApi);\n";
+        if (usePySideExtensions())
+            s << "QT_WARNING_POP\n";
+        s << '\n';
     }
 
     s << "// Create an array of primitive type converters for the current module.\n"
@@ -6179,8 +6434,13 @@ bool CppGenerator::finishGeneration()
         << "PyObject *module = Shiboken::Module::create(\""  << moduleName()
         << "\", &moduledef);\n\n"
         << "// Make module available from global scope\n"
-        << globalModuleVar << " = module;\n\n"
-        << "// Initialize classes in the type system\n"
+        << globalModuleVar << " = module;\n\n";
+
+    const QString subModuleOf = typeDb->defaultTypeSystemType()->subModuleOf();
+    if (!subModuleOf.isEmpty())
+        writeSubModuleHandling(s,  moduleName(), subModuleOf);
+
+    s << "// Initialize classes in the type system\n"
         << s_classPythonDefines.toString();
 
     if (!typeConversions.isEmpty()) {
@@ -6194,7 +6454,7 @@ bool CppGenerator::finishGeneration()
     if (!containers.isEmpty()) {
         s << '\n';
         for (const AbstractMetaType &container : containers) {
-            const QString converterObj = writeContainerConverterInitialization(s, container);
+            const QString converterObj = writeContainerConverterInitialization(s, container, api());
             const auto it = opaqueContainers.constFind(container);
             if (it !=  opaqueContainers.constEnd()) {
                 writeSetPythonToCppPointerConversion(s, converterObj,
@@ -6239,14 +6499,7 @@ bool CppGenerator::finishGeneration()
         if (!pte->referencesType())
             continue;
         TypeEntryCPtr referencedType = basicReferencedTypeEntry(pte);
-        QString converter = converterObject(referencedType);
-        QStringList cppSignature = pte->qualifiedCppName().split(u"::"_s, Qt::SkipEmptyParts);
-        while (!cppSignature.isEmpty()) {
-            QString signature = cppSignature.join(u"::"_s);
-            s << "Shiboken::Conversions::registerConverterName("
-                << converter << ", \"" << signature << "\");\n";
-            cppSignature.removeFirst();
-        }
+        registerConverterInScopes(s, pte->qualifiedCppName(), converterObject(referencedType));
     }
 
     s << '\n';
@@ -6260,11 +6513,12 @@ bool CppGenerator::finishGeneration()
         s << "\n// Static field initialization\n";
         for (const auto &cls : std::as_const(classesWithStaticFields)) {
             ConfigurableScope configScope(s, cls->typeEntry());
-            s << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n";
+            s << getSimpleClassStaticFieldsInitFunctionName(cls) << "(module);\n";
         }
     }
 
-    s << "\nif (" << shibokenErrorsOccurred << ") {\n" << indent
+    s << '\n' << initInheritanceFunction << "();\n"
+        << "\nif (" << shibokenErrorsOccurred << ") {\n" << indent
         << "PyErr_Print();\n"
         << "Py_FatalError(\"can't initialize module " << moduleName() << "\");\n"
         << outdent << "}\n";
@@ -6362,7 +6616,7 @@ bool CppGenerator::writeParentChildManagement(TextStream &s, const AbstractMetaF
             if (parentIndex == 0) {
                 parentVariable = PYTHON_RETURN_VAR;
             } else if (parentIndex == -1) {
-                parentVariable = u"self"_s;
+                parentVariable = PYTHON_SELF_VAR;
             } else {
                 parentVariable = usePyArgs
                     ? pythonArgsAt(parentIndex - 1) : PYTHON_ARG;
@@ -6372,7 +6626,7 @@ bool CppGenerator::writeParentChildManagement(TextStream &s, const AbstractMetaF
         if (childIndex == 0) {
             childVariable = PYTHON_RETURN_VAR;
         } else if (childIndex == -1) {
-            childVariable = u"self"_s;
+            childVariable = PYTHON_SELF_VAR;
         } else {
             childVariable = usePyArgs
                 ? pythonArgsAt(childIndex - 1) : PYTHON_ARG;
index 95ed0bf7dfe53416349016dbc65d19aae495de7f..f369ab01bdaac7438318f363f6943993ddaccee3 100644 (file)
@@ -49,13 +49,21 @@ protected:
     bool finishGeneration() override;
 
 private:
+    struct VirtualMethodReturn
+    {
+        QString statement;
+        bool needsReference = false;
+    };
+
+
     void generateSmartPointerClass(TextStream &s, const GeneratorContext &classContext);
     void generateIncludes(TextStream &s, const GeneratorContext &classContext,
                           const IncludeGroupList &includes = {},
                           const AbstractMetaClassCList &innerClasses = {}) const;
     static void writeInitFunc(TextStream &declStr, TextStream &callStr,
                               const QString &initFunctionName,
-                              const TypeEntryCPtr &enclosingEntry = {});
+                              const TypeEntryCPtr &enclosingEntry,
+                              const QString &pythonName, bool lazy = true);
     static void writeCacheResetNative(TextStream &s, const GeneratorContext &classContext);
     void writeConstructorNative(TextStream &s, const GeneratorContext &classContext,
                                 const AbstractMetaFunctionCPtr &func) const;
@@ -75,13 +83,20 @@ private:
     void writeVirtualMethodNative(TextStream &s,
                                   const AbstractMetaFunctionCPtr &func,
                                   int cacheIndex) const;
+    void writeVirtualMethodPythonOverride(TextStream &s,
+                                          const AbstractMetaFunctionCPtr &func,
+                                          const CodeSnipList &snips,
+                                          const VirtualMethodReturn &returnStatement) const;
+    void writeUserAddedPythonOverride(TextStream &s,
+                                      const AbstractMetaFunctionCPtr &func) const;
     void writeVirtualMethodCppCall(TextStream &s, const AbstractMetaFunctionCPtr &func,
                                    const QString &funcName, const QList<CodeSnip> &snips,
                                    const AbstractMetaArgument *lastArg, const TypeEntryCPtr &retType,
                                    const QString &returnStatement, bool hasGil) const;
-    static QString virtualMethodReturn(TextStream &s, const ApiExtractorResult &api,
-                                       const AbstractMetaFunctionCPtr &func,
-                                       const FunctionModificationList &functionModifications);
+
+    static VirtualMethodReturn virtualMethodReturn(const ApiExtractorResult &api,
+                                                   const AbstractMetaFunctionCPtr &func,
+                                                   const FunctionModificationList &functionModifications);
     void writeMetaObjectMethod(TextStream &s, const GeneratorContext &classContext) const;
     static void writeMetaCast(TextStream &s, const GeneratorContext &classContext);
 
@@ -179,6 +194,8 @@ private:
     static void writeTypeCheck(TextStream& s, const std::shared_ptr<OverloadDataNode> &overloadData,
                         const QString &argumentName);
 
+    static void replacePolymorphicIdPlaceHolders(const AbstractMetaClassCPtr &metaClass,
+                                                 QString *id);
     static void writeTypeDiscoveryFunction(TextStream &s,
                                            const AbstractMetaClassCPtr &metaClass);
 
@@ -378,10 +395,12 @@ private:
     static void writeSignatureStrings(TextStream &s, const QString &signatures,
                                       const QString &arrayName,
                                       const char *comment);
+    void writeInitInheritance(TextStream &s) const;
     void writeClassRegister(TextStream &s,
                             const AbstractMetaClassCPtr &metaClass,
                             const GeneratorContext &classContext,
                             const QString &signatures) const;
+    static QStringList pyBaseTypes(const AbstractMetaClassCPtr &metaClass);
     static QString destructorClassName(const AbstractMetaClassCPtr &metaClass,
                                        const GeneratorContext &classContext);
     static void writeStaticFieldInitialization(TextStream &s,
@@ -394,6 +413,7 @@ private:
 
     void writeSignatureInfo(TextStream &s, const OverloadData &overloads) const;
     QString signatureParameter(const AbstractMetaArgument &arg) const;
+    QString pythonSignature(const AbstractMetaType &type) const;
     /// Writes the implementation of all methods part of python sequence protocol
     void writeSequenceMethods(TextStream &s,
                               const AbstractMetaClassCPtr &metaClass,
@@ -459,8 +479,11 @@ private:
                                                       const CustomConversionPtr &customConversion);
     static void writeEnumConverterInitialization(TextStream &s, const AbstractMetaEnum &metaEnum);
     static QString writeContainerConverterInitialization(TextStream &s,
-                                                         const AbstractMetaType &type);
+                                                         const AbstractMetaType &type,
+                                                         const ApiExtractorResult &api);
     void writeSmartPointerConverterInitialization(TextStream &s, const AbstractMetaType &ype) const;
+
+    static QString typeInitStruct(const TypeEntryCPtr &te);
     static void writeExtendedConverterInitialization(TextStream &s,
                                                      const TypeEntryCPtr &externalType,
                                                      const AbstractMetaClassCList &conversions);
@@ -528,9 +551,6 @@ private:
     static bool hasBoolCast(const AbstractMetaClassCPtr &metaClass)
     { return boolCast(metaClass).has_value(); }
 
-    std::optional<AbstractMetaType>
-        findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer,
-                                      const TypeEntryCPtr &pointee) const;
     void clearTpFuncs();
     static QString chopType(QString s);
 
index f746ea71436d7ac8617ddfb6116615d5aa0cd359..00e0cabeac918a98e68f8872056d2bc2390a2dbc 100644 (file)
@@ -101,20 +101,17 @@ void CppGenerator::writeOpaqueContainerValueConverter(TextStream &s,
                                                       const AbstractMetaType &valueType) const
 {
     // Generate template specialization of value converter helper unless it is already there
-    const QString pyArg = u"pyArg"_s;
-    const QString cppArg = u"cppArg"_s;
-
     const QString valueTypeName = valueType.cppSignature();
     const QString checkFunction = cpythonCheckFunction(valueType);
 
     s << "template <>\nstruct ShibokenContainerValueConverter<"
       << valueTypeName << ">\n{\n";
     // Type check
-    s << indent << "static bool checkValue(PyObject *" << pyArg << ")\n{\n"
+    s << indent << "static bool checkValue(PyObject *" << PYTHON_ARG << ")\n{\n"
         << indent << "return " << checkFunction;
     if (!checkFunction.contains(u'('))
         s << '(';
-    s << pyArg << ");\n"
+    s << PYTHON_ARG << ");\n"
         << outdent << "}\n\n";
 
     // C++ to Python
@@ -126,21 +123,21 @@ void CppGenerator::writeOpaqueContainerValueConverter(TextStream &s,
     s << valueTypeName << ' ';
     if (passByConstRef)
         s << '&';
-    s << cppArg << ")\n{\n" << indent << "return ";
-    writeToPythonConversion(s, valueType, nullptr, cppArg);
+    s << CPP_ARG << ")\n{\n" << indent << "return ";
+    writeToPythonConversion(s, valueType, nullptr, CPP_ARG);
     s << ";\n" << outdent << "}\n\n";
 
     // Python to C++
     s << "static std::optional<" << valueTypeName << "> convertValueToCpp(PyObject *"
-        << pyArg << ")\n{\n" << indent;
+        << PYTHON_ARG << ")\n{\n" << indent;
     s << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR << ";\n"
         << "if (!(";
-    writeTypeCheck(s, valueType, pyArg), isNumber(valueType.typeEntry());
+    writeTypeCheck(s, valueType, PYTHON_ARG), isNumber(valueType.typeEntry());
     s << ")) {\n" << indent
         << "Shiboken::Errors::setWrongContainerType();\n"
         << "return {};\n" << outdent << "}\n";
-    writePythonToCppTypeConversion(s, valueType, pyArg, cppArg, nullptr, {});
-    s << "return " << cppArg << ";\n" << outdent << "}\n" << outdent << "};\n\n";
+    writePythonToCppTypeConversion(s, valueType, PYTHON_ARG, CPP_ARG, nullptr, {});
+    s << "return " << CPP_ARG << ";\n" << outdent << "}\n" << outdent << "};\n\n";
 }
 
 // Generate code for a type wrapping a C++ container instantiation
@@ -245,26 +242,25 @@ CppGenerator::OpaqueContainerData
 
     // Check function
     result.checkFunctionName = result.name + u"_Check"_s;
-    const QString pyArg = u"pyArg"_s;
-    s << "extern \"C\" int " << result.checkFunctionName << "(PyObject *" << pyArg
-        << ")\n{\n" << indent << "return " << pyArg << " != nullptr && "
-        << pyArg << " != Py_None && " << pyArg << "->ob_type == "
+    s << "extern \"C\" int " << result.checkFunctionName << "(PyObject *" << PYTHON_ARG
+        << ")\n{\n" << indent << "return " << PYTHON_ARG << " != nullptr && "
+        << PYTHON_ARG << " != Py_None && " << PYTHON_ARG << "->ob_type == "
         << typeFName << "();\n" << outdent << "}\n\n";
 
     // SBK converter Python to C++
     result.pythonToConverterFunctionName = u"PythonToCpp"_s + result.name;
     s << "extern \"C\" void " << result.pythonToConverterFunctionName
-        << "(PyObject *" << pyArg << ", void *cppOut)\n{\n" << indent
+        << "(PyObject *" << PYTHON_ARG << ", void *cppOut)\n{\n" << indent
         << "auto *d = ShibokenSequenceContainerPrivate<" << cppSignature
-        << ">::get(" << pyArg << ");\n"
+        << ">::get(" << PYTHON_ARG << ");\n"
         << "*reinterpret_cast<" << cppSignature << "**>(cppOut) = d->m_list;\n"
         << outdent << "}\n\n";
 
     // SBK check function for converting Python to C++ that returns the converter
     result.converterCheckFunctionName = u"is"_s + result.name + u"PythonToCppConvertible"_s;
     s << "extern \"C\" PythonToCppFunc " << result.converterCheckFunctionName
-        << "(PyObject *" << pyArg << ")\n{\n" << indent << "if ("
-        << result.checkFunctionName << '(' << pyArg << "))\n" << indent
+        << "(PyObject *" << PYTHON_ARG << ")\n{\n" << indent << "if ("
+        << result.checkFunctionName << '(' << PYTHON_ARG << "))\n" << indent
         << "return " << result.pythonToConverterFunctionName << ";\n"
         << outdent << "return {};\n" << outdent << "}\n\n";
 
index 1b893640a9d3c3bdbb395cf115c070447f31f05e..a00c2ba50b2cf8e7991fd2ab45a31a41acd47cd4 100644 (file)
@@ -86,18 +86,6 @@ static ComparisonOperatorList smartPointeeComparisons(const GeneratorContext &co
     return result;
 }
 
-std::optional<AbstractMetaType>
-    CppGenerator::findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer,
-                                                const TypeEntryCPtr &pointee) const
-{
-    for (const auto &smp : api().instantiatedSmartPointers()) {
-        const auto &i = smp.type;
-        if (i.typeEntry() == pointer && i.instantiations().at(0).typeEntry() == pointee)
-            return i;
-    }
-    return {};
-}
-
 static bool hasParameterPredicate(const AbstractMetaFunctionCPtr &f)
 {
     return !f->arguments().isEmpty();
@@ -252,8 +240,8 @@ void CppGenerator::writeSmartPointerConverterFunctions(TextStream &s,
     for (const auto &base : baseClasses) {
         auto baseTe = base->typeEntry();
         if (smartPointerTypeEntry->matchesInstantiation(baseTe)) {
-            if (auto opt = findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
-                const auto smartTargetType = opt.value();
+            if (auto opt = api().findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
+                const auto &smartTargetType = opt.value().type;
                 s << "// SmartPointer derived class: "
                   << smartTargetType.cppSignature() << "\n";
                 writePythonToCppConversionFunctions(s, smartPointerType,
@@ -308,8 +296,8 @@ void CppGenerator::writeSmartPointerConverterInitialization(TextStream &s,
 
     for (const auto &base : classes) {
         auto baseTe = base->typeEntry();
-        if (auto opt = findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
-            const auto smartTargetType = opt.value();
+        if (auto opt = api().findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
+            const auto &smartTargetType = opt.value().type;
             s << "// Convert to SmartPointer derived class: ["
               << smartTargetType.cppSignature() << "]\n";
             const QString converter = u"Shiboken::Conversions::getConverter(\""_s
index 0444c99f256dcf4ec98727c3fb1e37bd7743fac7..f665b30ff318e48bde44fee5774956d8449406ce 100644 (file)
@@ -6,26 +6,26 @@
 
 #include <QtCore/QString>
 
-static inline QString boolT() { return QStringLiteral("bool"); }
-static inline QString intT() { return QStringLiteral("int"); }
-static inline QString unsignedT() { return QStringLiteral("unsigned"); }
-static inline QString unsignedIntT() { return QStringLiteral("unsigned int"); }
-static inline QString longT() { return QStringLiteral("long"); }
-static inline QString unsignedLongT() { return QStringLiteral("unsigned long"); }
-static inline QString shortT() { return QStringLiteral("short"); }
-static inline QString unsignedShortT() { return QStringLiteral("unsigned short"); }
-static inline QString unsignedCharT() { return QStringLiteral("unsigned char"); }
-static inline QString longLongT() { return QStringLiteral("long long"); }
-static inline QString unsignedLongLongT() { return QStringLiteral("unsigned long long"); }
-static inline QString charT() { return QStringLiteral("char"); }
-static inline QString floatT() { return QStringLiteral("float"); }
-static inline QString doubleT() { return QStringLiteral("double"); }
-static inline QString constCharPtrT() { return QStringLiteral("const char*"); }
+constexpr auto boolT = QLatin1StringView("bool");
+constexpr auto intT = QLatin1StringView("int");
+constexpr auto unsignedT = QLatin1StringView("unsigned");
+constexpr auto unsignedIntT = QLatin1StringView("unsigned int");
+constexpr auto longT = QLatin1StringView("long");
+constexpr auto unsignedLongT = QLatin1StringView("unsigned long");
+constexpr auto shortT = QLatin1StringView("short");
+constexpr auto unsignedShortT = QLatin1StringView("unsigned short");
+constexpr auto unsignedCharT = QLatin1StringView("unsigned char");
+constexpr auto longLongT = QLatin1StringView("long long");
+constexpr auto unsignedLongLongT = QLatin1StringView("unsigned long long");
+constexpr auto charT = QLatin1StringView("char");
+constexpr auto floatT = QLatin1StringView("float");
+constexpr auto doubleT = QLatin1StringView("double");
+constexpr auto constCharPtrT = QLatin1StringView("const char*");
 
-static inline QString qByteArrayT() { return QStringLiteral("QByteArray"); }
-static inline QString qMetaObjectT() { return QStringLiteral("QMetaObject"); }
-static inline QString qObjectT() { return QStringLiteral("QObject"); }
-static inline QString qStringT() { return QStringLiteral("QString"); }
-static inline QString qVariantT() { return QStringLiteral("QVariant"); }
+constexpr auto qByteArrayT = QLatin1StringView("QByteArray");
+constexpr auto qMetaObjectT = QLatin1StringView("QMetaObject");
+constexpr auto qObjectT = QLatin1StringView("QObject");
+constexpr auto qStringT = QLatin1StringView("QString");
+constexpr auto qVariantT = QLatin1StringView("QVariant");
 
 #endif // CTYPENAMES_H
index 6751d5216408fc7bb7cfff145b4b84a4ae0c0e2b..9ce91e5990f37aa9447be128c46aebe9dc9e048d 100644 (file)
@@ -6,25 +6,30 @@
 
 #include <QtCore/QString>
 
-QString CPP_ARG(int i);
+QString CPP_ARG_N(int i);
 QString CPP_ARG_REMOVED(int i);
 
-extern const QString CPP_RETURN_VAR;
-extern const QString CPP_SELF_VAR;
-extern const QString NULL_PTR;
-extern const QString PYTHON_ARG;
-extern const QString PYTHON_ARGS;
-extern const QString PYTHON_OVERRIDE_VAR;
-extern const QString PYTHON_RETURN_VAR;
-extern const QString PYTHON_TO_CPP_VAR;
+constexpr auto CPP_RETURN_VAR = QLatin1StringView("cppResult");
+constexpr auto CPP_SELF_VAR = QLatin1StringView("cppSelf");
+constexpr auto CPP_ARG = QLatin1StringView("cppArg");
+constexpr auto NULL_PTR = QLatin1StringView("nullptr");
+constexpr auto PYTHON_ARG = QLatin1StringView("pyArg");
+constexpr auto PYTHON_ARGS = QLatin1StringView("pyArgs");
+constexpr auto PYTHON_OVERRIDE_VAR = QLatin1StringView("pyOverride");
+constexpr auto PYTHON_RETURN_VAR = QLatin1StringView("pyResult");
+constexpr auto PYTHON_SELF_VAR = QLatin1StringView("self");
+constexpr auto PYTHON_TO_CPP_VAR = QLatin1StringView("pythonToCpp");
 
-extern const QString CONV_RULE_OUT_VAR_SUFFIX;
-extern const QString BEGIN_ALLOW_THREADS;
-extern const QString END_ALLOW_THREADS;
+constexpr auto CONV_RULE_OUT_VAR_SUFFIX = QLatin1StringView("_out");
+constexpr auto BEGIN_ALLOW_THREADS
+    = QLatin1StringView("PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS");
+constexpr auto END_ALLOW_THREADS
+    = QLatin1StringView("PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS");
 
-extern const QString REPR_FUNCTION;
+constexpr auto REPR_FUNCTION = QLatin1StringView("__repr__");
+
+constexpr auto CPP_ARG0 = QLatin1StringView("cppArg0");
 
-extern const QString CPP_ARG0;
 extern const char *const METHOD_DEF_SENTINEL;
 extern const char *const PYTHON_TO_CPPCONVERSION_STRUCT;
 extern const char *const openTargetExternC;
index 9f6de35605bd05d170d65296ca7b0f55456c557a..35d0d114f8b488c77eaef2db2b9cd6ec226a637f 100644 (file)
 
 using namespace Qt::StringLiterals;
 
+struct IndexValue
+{
+    QString name; // "SBK_..."
+    int value;
+    QString comment;
+};
+
+TextStream &operator<<(TextStream &s, const IndexValue &iv)
+{
+    s << "    " << AlignedField(iv.name, 56) << " = " << iv.value << ',';
+    if (!iv.comment.isEmpty())
+        s << " // " << iv.comment;
+    s << '\n';
+    return s;
+}
+
 //  PYSIDE-504: Handling the "protected hack"
 //  The problem: Creating wrappers when the class has private destructors.
 //  You can see an example on Windows in qclipboard_wrapper.h and others.
@@ -101,7 +117,7 @@ void HeaderGenerator::generateClass(TextStream &s, const GeneratorContext &class
     s << licenseComment();
 
     QString wrapperName = classContext.effectiveClassName();
-    QString outerHeaderGuard = getFilteredCppSignatureString(wrapperName).toUpper();
+    QString outerHeaderGuard = getFilteredCppSignatureString(wrapperName);
 
     // Header
     s << "#ifndef SBK_" << outerHeaderGuard << "_H\n";
@@ -110,7 +126,7 @@ void HeaderGenerator::generateClass(TextStream &s, const GeneratorContext &class
     if (!avoidProtectedHack())
         s << protectedHackDefine;
 
-    //Includes
+    // Includes
     s << metaClass->typeEntry()->include() << '\n';
     for (auto &inst : metaClass->templateBaseClassInstantiations())
         s << inst.typeEntry()->include();
@@ -240,10 +256,10 @@ void HeaderGenerator::writeWrapperClassDeclaration(TextStream &s,
                         TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode,
                         classContext);
 
-    if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
-        && usePySideExtensions() && isQObject(metaClass)) {
-        s << outdent << "public:\n" << indent <<
-            R"(int qt_metacall(QMetaObject::Call call, int id, void **args) override;
+    if (shouldGenerateMetaObjectFunctions(metaClass)) {
+        s << R"(
+const ::QMetaObject * metaObject() const override;
+int qt_metacall(QMetaObject::Call call, int id, void **args) override;
 void *qt_metacast(const char *_clname) override;
 )";
     }
@@ -258,8 +274,15 @@ void *qt_metacast(const char *_clname) override;
         s << "static void pysideInitQtMetaTypes();\n";
 
     s << "void resetPyMethodCache();\n"
-      << outdent << "private:\n" << indent
-      << "mutable bool m_PyMethodCache[" << maxOverrides << "];\n"
+        << outdent << "private:\n" << indent;
+
+    if (!metaClass->userAddedPythonOverrides().isEmpty()) {
+        for (const auto &f : metaClass->userAddedPythonOverrides())
+            s << functionSignature(f, {}, {}, Generator::OriginalTypeDescription) << ";\n";
+        s << '\n';
+    }
+
+    s << "mutable bool m_PyMethodCache[" << maxOverrides << "];\n"
       << outdent << "};\n\n";
 }
 
@@ -270,8 +293,6 @@ void HeaderGenerator::writeMemberFunctionWrapper(TextStream &s,
 {
     Q_ASSERT(!func->isConstructor() && !func->isOperatorOverload());
     s << "inline ";
-    if (func->isStatic())
-        s << "static ";
     s << functionSignature(func, {}, postfix, Generator::OriginalTypeDescription)
       << " { ";
     if (!func->isVoid())
@@ -330,7 +351,7 @@ void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPt
     }
 
     const bool isVirtual = generation.testFlag(FunctionGenerationFlag::VirtualMethod);
-    if (isVirtual || generation.testFlag(FunctionGenerationFlag::QMetaObjectMethod)) {
+    if (isVirtual) {
         s << functionSignature(func, {}, {}, Generator::OriginalTypeDescription)
             << " override;\n";
     }
@@ -355,20 +376,6 @@ void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPt
     }
 }
 
-static void _writeTypeIndexValue(TextStream &s, const QString &variableName,
-                                 int typeIndex)
-{
-    s << "    " << AlignedField(variableName, 56) << " = " << typeIndex;
-}
-
-static inline void _writeTypeIndexValueLine(TextStream &s,
-                                            const QString &variableName,
-                                            int typeIndex)
-{
-    _writeTypeIndexValue(s, variableName, typeIndex);
-    s << ",\n";
-}
-
 // Find equivalent typedefs "using Foo=QList<int>", "using Bar=QList<int>"
 static AbstractMetaClassCPtr
     findEquivalentTemplateTypedef(const AbstractMetaClassCList &haystack,
@@ -386,14 +393,15 @@ static AbstractMetaClassCPtr
     return nullptr;
 }
 
-void HeaderGenerator::writeTypeIndexValueLine(TextStream &s, const ApiExtractorResult &api,
-                                              const TypeEntryCPtr &typeEntry)
+void HeaderGenerator::collectTypeEntryTypeIndexes(const ApiExtractorResult &api,
+                                                  const TypeEntryCPtr &typeEntry,
+                                                  IndexValues *indexValues)
 {
     if (!typeEntry || !typeEntry->generateCode())
         return;
-    s.setFieldAlignment(QTextStream::AlignLeft);
     const int typeIndex = typeEntry->sbkIndex();
-    _writeTypeIndexValueLine(s, getTypeIndexVariableName(typeEntry), typeIndex);
+    indexValues->append({getTypeIndexVariableName(typeEntry), typeIndex, {}});
+
     if (typeEntry->isComplex()) {
         // For a typedef "using Foo=QList<int>", write a type index
         // SBK_QLIST_INT besides SBK_FOO which is then matched by function
@@ -408,7 +416,7 @@ void HeaderGenerator::writeTypeIndexValueLine(TextStream &s, const ApiExtractorR
                                                  metaClass) == nullptr) {
                 const QString indexVariable =
                     getTypeAlternateTemplateIndexVariableName(metaClass);
-                _writeTypeIndexValueLine(s, indexVariable, typeIndex);
+                indexValues->append({indexVariable, typeIndex, {}});
                 m_alternateTemplateIndexes.append(m_alternateTemplateIndexes);
             }
         }
@@ -416,12 +424,13 @@ void HeaderGenerator::writeTypeIndexValueLine(TextStream &s, const ApiExtractorR
     if (typeEntry->isEnum()) {
         auto ete = std::static_pointer_cast<const EnumTypeEntry>(typeEntry);
         if (ete->flags())
-            writeTypeIndexValueLine(s, api, ete->flags());
+            collectTypeEntryTypeIndexes(api, ete->flags(), indexValues);
     }
 }
 
-void HeaderGenerator::writeTypeIndexValueLines(TextStream &s, const ApiExtractorResult &api,
-                                               const AbstractMetaClassCPtr &metaClass)
+void HeaderGenerator::collectClassTypeIndexes(const ApiExtractorResult &api,
+                                              const AbstractMetaClassCPtr &metaClass,
+                                              IndexValues *indexValues)
 {
     auto typeEntry = metaClass->typeEntry();
     if (!typeEntry->generateCode())
@@ -429,10 +438,10 @@ void HeaderGenerator::writeTypeIndexValueLines(TextStream &s, const ApiExtractor
     // enum indices are required for invisible namespaces as well.
     for (const AbstractMetaEnum &metaEnum : metaClass->enums()) {
         if (!metaEnum.isPrivate())
-            writeTypeIndexValueLine(s, api, metaEnum.typeEntry());
+            collectTypeEntryTypeIndexes(api, metaEnum.typeEntry(), indexValues);
     }
     if (NamespaceTypeEntry::isVisibleScope(typeEntry))
-        writeTypeIndexValueLine(s, api, typeEntry);
+        collectTypeEntryTypeIndexes(api, typeEntry, indexValues);
 }
 
 // Format the typedefs for the typedef entries to be generated
@@ -537,6 +546,11 @@ static void writeForwardDeclarations(TextStream &s,
 {
     NameSpaces nameSpaces;
 
+    s << '\n';
+    auto typeSystemEntry = TypeDatabase::instance()->defaultTypeSystemType();
+    if (!typeSystemEntry->namespaceBegin().isEmpty())
+        s << typeSystemEntry->namespaceBegin() << '\n';
+
     for (const auto &c : classList) {
         if (auto encl = c->enclosingClass()) {
             Q_ASSERT(encl->isNamespace());
@@ -565,6 +579,9 @@ static void writeForwardDeclarations(TextStream &s,
         if (nsp.nameSpace->enclosingClass() == nullptr)
             writeNamespaceForwardDeclarationRecursion(s, i, nameSpaces);
     }
+
+    if (!typeSystemEntry->namespaceEnd().isEmpty())
+        s << typeSystemEntry->namespaceEnd() << '\n';
 }
 
 // Include parameters required for the module/private module header
@@ -586,91 +603,132 @@ struct ModuleHeaderParameters
     QString typeFunctions;
 };
 
-bool HeaderGenerator::finishGeneration()
+HeaderGenerator::IndexValues
+    HeaderGenerator::collectTypeIndexes(const AbstractMetaClassCList &classList)
 {
-    // Generate the main header for this module. This header should be included
-    // by binding modules extending on top of this one.
-    ModuleHeaderParameters parameters;
-    ModuleHeaderParameters privateParameters;
-    StringStream macrosStream(TextStream::Language::Cpp);
-
-    const auto snips = TypeDatabase::instance()->defaultTypeSystemType()->codeSnips();
-    writeModuleCodeSnips(macrosStream, snips, TypeSystem::CodeSnipPositionDeclaration,
-                         TypeSystem::TargetLangCode);
-
-    macrosStream << "// Type indices\nenum : int {\n";
-    auto classList = api().classes();
-
-    std::sort(classList.begin(), classList.end(),
-              [](const AbstractMetaClassCPtr &a, const AbstractMetaClassCPtr &b) {
-                  return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex();
-              });
+    IndexValues result;
 
     for (const auto &metaClass : classList)
-        writeTypeIndexValueLines(macrosStream, api(), metaClass);
+        collectClassTypeIndexes(api(), metaClass, &result);
 
     for (const AbstractMetaEnum &metaEnum : api().globalEnums())
-        writeTypeIndexValueLine(macrosStream, api(), metaEnum.typeEntry());
+        collectTypeEntryTypeIndexes(api(), metaEnum.typeEntry(), &result);
 
     // Write the smart pointer define indexes.
     int smartPointerCountIndex = getMaxTypeIndex();
     int smartPointerCount = 0;
     for (const auto &smp : api().instantiatedSmartPointers()) {
         QString indexName = getTypeIndexVariableName(smp.type);
-        _writeTypeIndexValue(macrosStream, indexName, smartPointerCountIndex);
-        macrosStream << ", // " << smp.type.cppSignature() << '\n';
+        result.append({indexName, smartPointerCountIndex, smp.type.cppSignature()});
         // Add a the same value for const pointees (shared_ptr<const Foo>).
         const auto ptrName = smp.type.typeEntry()->entryName();
         const auto pos = indexName.indexOf(ptrName, 0, Qt::CaseInsensitive);
         if (pos >= 0) {
-            indexName.insert(pos + ptrName.size() + 1, u"CONST"_s);
-            _writeTypeIndexValue(macrosStream, indexName, smartPointerCountIndex);
-            macrosStream << ", //   (const)\n";
+            indexName.insert(pos + ptrName.size() + 1, u"const"_s);
+            result.append({indexName, smartPointerCountIndex, "(const)"_L1});
         }
         ++smartPointerCountIndex;
         ++smartPointerCount;
     }
+    result.append({"SBK_"_L1 + moduleName() + "_IDX_COUNT"_L1,
+                  getMaxTypeIndex() + smartPointerCount, {}});
+    return result;
+}
 
-    _writeTypeIndexValue(macrosStream,
-                         u"SBK_"_s + moduleName() + u"_IDX_COUNT"_s,
-                         getMaxTypeIndex() + smartPointerCount);
-    macrosStream << "\n};\n";
-
-    macrosStream << "// This variable stores all Python types exported by this module.\n";
-    macrosStream << "extern PyTypeObject **" << cppApiVariableName() << ";\n\n";
-    macrosStream << "// This variable stores the Python module object exported by this module.\n";
-    macrosStream << "extern PyObject *" << pythonModuleObjectName() << ";\n\n";
-    macrosStream << "// This variable stores all type converters exported by this module.\n";
-    macrosStream << "extern SbkConverter **" << convertersVariableName() << ";\n\n";
-
-    // TODO-CONVERTER ------------------------------------------------------------------------------
-    // Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex().
-    macrosStream << "// Converter indices\nenum : int {\n";
+HeaderGenerator::IndexValues HeaderGenerator::collectConverterIndexes() const
+{
+    IndexValues result;
     const auto &primitives = primitiveTypes();
     int pCount = 0;
     for (const auto &ptype : primitives) {
-        /* Note: do not generate indices for typedef'd primitive types
-         * as they'll use the primitive type converters instead, so we
-         * don't need to create any other.
-         */
-        if (!ptype->generateCode() || !ptype->customConversion())
-            continue;
-
-        _writeTypeIndexValueLine(macrosStream, getTypeIndexVariableName(ptype), pCount++);
+        // Note: do not generate indices for typedef'd primitive types as
+        // they'll use the primitive type converters instead, so we
+        // don't need to create any other.
+        if (ptype->generateCode() && ptype->customConversion() != nullptr)
+            result.append({getTypeIndexVariableName(ptype), pCount++, {}});
     }
 
     for (const AbstractMetaType &container : api().instantiatedContainers()) {
-        _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(container), pCount);
-        macrosStream << ", // " << container.cppSignature() << '\n';
-        pCount++;
+        result.append({getTypeIndexVariableName(container),
+                       pCount++, container.cppSignature()});
     }
 
     // Because on win32 the compiler will not accept a zero length array.
     if (pCount == 0)
         pCount++;
-    _writeTypeIndexValue(macrosStream, QStringLiteral("SBK_%1_CONVERTERS_IDX_COUNT")
-                                       .arg(moduleName()), pCount);
-    macrosStream << "\n};\n";
+     result.append({"SBK_"_L1 + moduleName() + "_CONVERTERS_IDX_COUNT"_L1,
+                   pCount, {}});
+    return result;
+}
+
+// PYSIDE-2404: Write the enums in unchanged case for reuse in type imports.
+//              For conpatibility, we create them in uppercase, too and with
+//              doubled index for emulating the former type-only case.
+//
+// FIXME: Remove in PySide 7. (See the note in `parser.py`)
+//
+static IndexValue typeIndexUpper(struct IndexValue const &ti)
+{
+    QString modi = ti.name.toUpper();
+    if (modi == ti.name)
+        modi = u"// "_s + modi;
+    return {modi, ti.value * 2, ti.comment};
+}
+
+bool HeaderGenerator::finishGeneration()
+{
+    // Generate the main header for this module. This header should be included
+    // by binding modules extending on top of this one.
+    ModuleHeaderParameters parameters;
+    ModuleHeaderParameters privateParameters;
+    StringStream macrosStream(TextStream::Language::Cpp);
+
+    const auto snips = TypeDatabase::instance()->defaultTypeSystemType()->codeSnips();
+    writeModuleCodeSnips(macrosStream, snips, TypeSystem::CodeSnipPositionDeclaration,
+                         TypeSystem::TargetLangCode);
+
+    auto classList = api().classes();
+
+    std::sort(classList.begin(), classList.end(),
+              [](const AbstractMetaClassCPtr &a, const AbstractMetaClassCPtr &b) {
+                  return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex();
+              });
+
+    const auto typeIndexes = collectTypeIndexes(classList);
+
+    macrosStream << "\n// Type indices\nenum [[deprecated]] : int {\n";
+    for (const auto &ti : typeIndexes)
+        macrosStream << typeIndexUpper(ti);
+    macrosStream << "};\n";
+
+    macrosStream << "\n// Type indices\nenum : int {\n";
+    for (const auto &ti : typeIndexes)
+        macrosStream << ti;
+    macrosStream << "};\n\n";
+
+    // FIXME: Remove backwards compatible variable in PySide 7.
+    macrosStream << "// This variable stores all Python types exported by this module.\n";
+    macrosStream << "extern Shiboken::Module::TypeInitStruct *" << cppApiVariableName() << ";\n\n";
+    macrosStream << "// This variable stores all Python types exported by this module ";
+    macrosStream << "in a backwards compatible way with identical indexing.\n";
+    macrosStream << "[[deprecated]] extern PyTypeObject **" << cppApiVariableNameOld() << ";\n\n";
+    macrosStream << "// This variable stores the Python module object exported by this module.\n";
+    macrosStream << "extern PyObject *" << pythonModuleObjectName() << ";\n\n";
+    macrosStream << "// This variable stores all type converters exported by this module.\n";
+    macrosStream << "extern SbkConverter **" << convertersVariableName() << ";\n\n";
+
+    // TODO-CONVERTER ------------------------------------------------------------------------------
+    // Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex().
+    const auto converterIndexes = collectConverterIndexes();
+    macrosStream << "// Converter indices\nenum [[deprecated]] : int {\n";
+    for (const auto &ci : converterIndexes)
+        macrosStream << typeIndexUpper(ci);
+    macrosStream << "};\n\n";
+
+    macrosStream << "// Converter indices\nenum : int {\n";
+    for (const auto &ci : converterIndexes)
+        macrosStream << ci;
+    macrosStream << "};\n";
 
     formatTypeDefEntries(macrosStream);
 
@@ -698,7 +756,7 @@ bool HeaderGenerator::finishGeneration()
         if (!shouldGenerate(classType))
             continue;
 
-        //Includes
+        // Includes
         const bool isPrivate = classType->isPrivate();
         auto &par = isPrivate ? privateParameters : parameters;
         const auto classInclude = classType->include();
@@ -752,6 +810,7 @@ bool HeaderGenerator::finishGeneration()
     }
 
     s << "#include <sbkpython.h>\n";
+    s << "#include <sbkmodule.h>\n";
     s << "#include <sbkconverter.h>\n";
 
     QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports();
@@ -816,8 +875,7 @@ void HeaderGenerator::writePrivateHeader(const QString &moduleHeaderDir,
     TextStream &ps = privateFile.stream;
     ps.setLanguage(TextStream::Language::Cpp);
     QString privateIncludeShield =
-        publicIncludeShield.left(publicIncludeShield.size() - 2)
-        + QStringLiteral("_P_H");
+        publicIncludeShield.left(publicIncludeShield.size() - 2) + "_P_H"_L1;
 
     ps << licenseComment()<< "\n\n";
 
@@ -868,12 +926,12 @@ void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum
         : cppEnum.qualifiedCppName();
     const auto te = cppEnum.typeEntry();
     ConfigurableScope configScope(s, te);
-    s << "template<> inline PyTypeObject *SbkType< ::" << enumName << " >() ";
+    s << "template<> inline PyTypeObject *SbkType< " << m_gsp << enumName << " >() ";
     s << "{ return " << cpythonTypeNameExt(te) << "; }\n";
 
     const auto flag = cppEnum.typeEntry()->flags();
     if (flag) {
-        s <<  "template<> inline PyTypeObject *SbkType< ::" << flag->name() << " >() "
+        s <<  "template<> inline PyTypeObject *SbkType< " << m_gsp << flag->name() << " >() "
           << "{ return " << cpythonTypeNameExt(flag) << "; }\n";
     }
 }
@@ -882,13 +940,13 @@ void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaClas
 {
     s << "template<> inline PyTypeObject *SbkType< "
       << getFullTypeName(cppClass) << " >() "
-      << "{ return reinterpret_cast<PyTypeObject *>("
-      << cpythonTypeNameExt(cppClass->typeEntry()) << "); }\n";
+      << "{ return " << cpythonTypeNameExt(cppClass->typeEntry()) << "; }\n";
 }
 
 void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaType &metaType)
 {
-    s <<  "template<> inline PyTypeObject *SbkType< ::" << metaType.cppSignature() << " >() "
+    s <<  "template<> inline PyTypeObject *SbkType< "
+      << m_gsp << metaType.cppSignature() << " >() "
       <<  "{ return " << cpythonTypeNameExt(metaType) << "; }\n";
 }
 
index e986ff405907213a1740b3e04b74033cf2546856..03b98e7438a097224603d39a01f71de9a9386cde 100644 (file)
@@ -8,8 +8,10 @@
 #include "include.h"
 #include "modifications_typedefs.h"
 
+#include <QtCore/QList>
 #include <QtCore/QSet>
 
+struct IndexValue;
 class AbstractMetaFunction;
 struct ModuleHeaderParameters;
 
@@ -30,6 +32,10 @@ protected:
 
 private:
     using InheritedOverloadSet = QSet<AbstractMetaFunctionCPtr>;
+    using IndexValues = QList<IndexValue>;
+
+    IndexValues collectTypeIndexes(const AbstractMetaClassCList &classList);
+    IndexValues collectConverterIndexes() const;
 
     static void writeCopyCtor(TextStream &s, const AbstractMetaClassCPtr &metaClass);
     void writeFunction(TextStream &s,
@@ -39,10 +45,12 @@ private:
     static void writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum &cppEnum);
     static void writeSbkTypeFunction(TextStream &s, const AbstractMetaClassCPtr &cppClass);
     static void writeSbkTypeFunction(TextStream &s, const AbstractMetaType &metaType);
-    void writeTypeIndexValueLine(TextStream &s, const ApiExtractorResult &api,
-                                 const TypeEntryCPtr &typeEntry);
-    void writeTypeIndexValueLines(TextStream &s, const ApiExtractorResult &api,
-                                  const AbstractMetaClassCPtr &metaClass);
+    void collectTypeEntryTypeIndexes(const ApiExtractorResult &api,
+                                     const TypeEntryCPtr &typeEntry,
+                                     IndexValues *indexValues);
+    void collectClassTypeIndexes(const ApiExtractorResult &api,
+                                 const AbstractMetaClassCPtr &metaClass,
+                                 IndexValues *indexValues);
     static void writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum);
     void writeMemberFunctionWrapper(TextStream &s,
                                     const AbstractMetaFunctionCPtr &func,
index c1e965fec8e98042416725a92a77584a717f3471..c28fcdc1a196f967cf262cee06bb82c3ca40c245 100644 (file)
@@ -135,10 +135,10 @@ void OverloadDataRootNode::sortNextOverloads(const ApiExtractorResult &api)
 
     // Primitive types that are not int, long, short,
     // char and their respective unsigned counterparts.
-    static const QStringList nonIntegerPrimitives{floatT(), doubleT(), boolT()};
+    static const QStringList nonIntegerPrimitives{floatT, doubleT, boolT};
 
     // Signed integer primitive types.
-    static const QStringList signedIntegerPrimitives{intT(), shortT(), longT(), longLongT()};
+    static const QStringList signedIntegerPrimitives{intT, shortT, longT, longLongT};
 
     // sort the children overloads
     for (const auto &ov : std::as_const(m_children))
@@ -162,15 +162,15 @@ void OverloadDataRootNode::sortNextOverloads(const ApiExtractorResult &api)
             it.value().append(ov);
         }
 
-        if (!checkPyObject && typeName == cPyObjectT())
+        if (!checkPyObject && typeName == cPyObjectT)
             checkPyObject = true;
-        else if (!checkPySequence && typeName == cPySequenceT())
+        else if (!checkPySequence && typeName == cPySequenceT)
             checkPySequence = true;
-        else if (!checkPyBuffer && typeName == cPyBufferT())
+        else if (!checkPyBuffer && typeName == cPyBufferT)
             checkPyBuffer = true;
-        else if (!checkQVariant && typeName == qVariantT())
+        else if (!checkQVariant && typeName == qVariantT)
             checkQVariant = true;
-        else if (!checkQString && typeName == qStringT())
+        else if (!checkQString && typeName == qStringT)
             checkQString = true;
 
         for (const auto &instantiation : ov->argType().instantiations()) {
@@ -196,9 +196,9 @@ void OverloadDataRootNode::sortNextOverloads(const ApiExtractorResult &api)
 
     // Create the graph of type dependencies based on implicit conversions.
     // All C++ primitive types, add any forgotten type AT THE END OF THIS LIST!
-    static const QStringList primitiveTypes{intT(), unsignedIntT(), longT(), unsignedLongT(),
-        shortT(), unsignedShortT(), boolT(), unsignedCharT(), charT(), floatT(),
-        doubleT(), constCharPtrT()};
+    static const QStringList primitiveTypes{intT, unsignedIntT, longT, unsignedLongT,
+        shortT, unsignedShortT, boolT, unsignedCharT, charT, floatT,
+        doubleT, constCharPtrT};
 
     QStringList foundPrimitiveTypeIds;
     for (const auto &p : primitiveTypes) {
@@ -207,7 +207,7 @@ void OverloadDataRootNode::sortNextOverloads(const ApiExtractorResult &api)
     }
 
     if (checkPySequence && checkPyObject)
-        graph.addEdge(cPySequenceT(), cPyObjectT());
+        graph.addEdge(cPySequenceT, cPyObjectT);
 
     QStringList classesWithIntegerImplicitConversion;
 
@@ -226,7 +226,7 @@ void OverloadDataRootNode::sortNextOverloads(const ApiExtractorResult &api)
             else
                 convertibleType = getTypeName(function->arguments().constFirst().type());
 
-            if (convertibleType == intT() || convertibleType == unsignedIntT())
+            if (convertibleType == intT || convertibleType == unsignedIntT)
                 classesWithIntegerImplicitConversion << targetTypeEntryName;
 
             if (!graph.hasNode(convertibleType))
@@ -288,28 +288,28 @@ void OverloadDataRootNode::sortNextOverloads(const ApiExtractorResult &api)
 
 
         if ((checkPySequence || checkPyObject || checkPyBuffer)
-            && !targetTypeEntryName.contains(cPyObjectT())
-            && !targetTypeEntryName.contains(cPyBufferT())
-            && !targetTypeEntryName.contains(cPySequenceT())) {
+            && !targetTypeEntryName.contains(cPyObjectT)
+            && !targetTypeEntryName.contains(cPyBufferT)
+            && !targetTypeEntryName.contains(cPySequenceT)) {
             if (checkPySequence) {
                 // PySequence will be checked after all more specific types, but before PyObject.
-                graph.addEdge(targetTypeEntryName, cPySequenceT());
+                graph.addEdge(targetTypeEntryName, cPySequenceT);
             } else if (checkPyBuffer) {
                 // PySequence will be checked after all more specific types, but before PyObject.
-                graph.addEdge(targetTypeEntryName, cPyBufferT());
+                graph.addEdge(targetTypeEntryName, cPyBufferT);
             } else {
                 // Add dependency on PyObject, so its check is the last one (too generic).
-                graph.addEdge(targetTypeEntryName, cPyObjectT());
+                graph.addEdge(targetTypeEntryName, cPyObjectT);
             }
-        } else if (checkQVariant && targetTypeEntryName != qVariantT()) {
-            if (!graph.containsEdge(qVariantT(), targetTypeEntryName)) // Avoid cyclic dependency.
-                graph.addEdge(targetTypeEntryName, qVariantT());
+        } else if (checkQVariant && targetTypeEntryName != qVariantT) {
+            if (!graph.containsEdge(qVariantT, targetTypeEntryName)) // Avoid cyclic dependency.
+                graph.addEdge(targetTypeEntryName, qVariantT);
         } else if (checkQString && ov->argType().isPointer()
-            && targetTypeEntryName != qStringT()
-            && targetTypeEntryName != qByteArrayT()
-            && (!checkPyObject || targetTypeEntryName != cPyObjectT())) {
-            if (!graph.containsEdge(qStringT(), targetTypeEntryName)) // Avoid cyclic dependency.
-                graph.addEdge(targetTypeEntryName, qStringT());
+            && targetTypeEntryName != qStringT
+            && targetTypeEntryName != qByteArrayT
+            && (!checkPyObject || targetTypeEntryName != cPyObjectT)) {
+            if (!graph.containsEdge(qStringT, targetTypeEntryName)) // Avoid cyclic dependency.
+                graph.addEdge(targetTypeEntryName, qStringT);
         }
 
         if (targetType.isEnum()) {
@@ -320,14 +320,14 @@ void OverloadDataRootNode::sortNextOverloads(const ApiExtractorResult &api)
     }
 
     // QByteArray args need to be checked after QString args
-    if (graph.hasNode(qStringT()) && graph.hasNode(qByteArrayT()))
-        graph.addEdge(qStringT(), qByteArrayT());
+    if (graph.hasNode(qStringT) && graph.hasNode(qByteArrayT))
+        graph.addEdge(qStringT, qByteArrayT);
 
     static const Edge rangeOrder[] =
-        {{doubleT(), floatT()},
-         {longLongT(), longT()}, {longLongT(), intT()}, {intT(), shortT()},
-         {unsignedLongLongT(), unsignedLongT()}, {unsignedLongLongT(), unsignedT()},
-         {unsignedLongLongT(), unsignedIntT()}, {unsignedT(), unsignedShortT()}
+        {{doubleT, floatT},
+         {longLongT, longT}, {longLongT, intT}, {intT, shortT},
+         {unsignedLongLongT, unsignedLongT}, {unsignedLongLongT, unsignedT},
+         {unsignedLongLongT, unsignedIntT}, {unsignedT, unsignedShortT}
     };
     for (const auto &r : rangeOrder) {
         if (graph.hasNode(r.first) && graph.hasNode(r.second))
index 696e0d88d19714a5234171424163eece4d7213ea..6c7658ff69619acc74dc869c5287c5144e69fcb5 100644 (file)
@@ -6,24 +6,24 @@
 
 #include <QtCore/QString>
 
-static inline QString pyBoolT() { return QStringLiteral("PyBool"); }
-static inline QString pyFloatT() { return QStringLiteral("PyFloat"); }
-static inline QString pyLongT() { return QStringLiteral("PyLong"); }
-static inline QString pyObjectT() { return QStringLiteral("object"); }
-static inline QString pyStrT() { return QStringLiteral("str"); }
+constexpr auto pyBoolT = QLatin1StringView ("PyBool");
+constexpr auto pyFloatT = QLatin1StringView ("PyFloat");
+constexpr auto pyLongT = QLatin1StringView ("PyLong");
+constexpr auto pyObjectT = QLatin1StringView ("object");
+constexpr auto pyStrT = QLatin1StringView ("str");
 
 // PYSIDE-1499: A custom type determined by existence of an `__fspath__` attribute.
-static inline QString pyPathLikeT() { return QStringLiteral("PyPathLike"); }
+constexpr auto pyPathLikeT = QLatin1StringView ("PyPathLike");
 
-static inline QString cPyBufferT() { return QStringLiteral("PyBuffer"); }
-static inline QString cPyListT() { return QStringLiteral("PyList"); }
-static inline QString cPyObjectT() { return QStringLiteral("PyObject"); }
-static inline QString cPySequenceT() { return QStringLiteral("PySequence"); }
-static inline QString cPyTypeObjectT() { return QStringLiteral("PyTypeObject"); }
+constexpr auto cPyBufferT = QLatin1StringView ("PyBuffer");
+constexpr auto cPyListT = QLatin1StringView ("PyList");
+constexpr auto cPyObjectT = QLatin1StringView ("PyObject");
+constexpr auto cPySequenceT = QLatin1StringView ("PySequence");
+constexpr auto cPyTypeObjectT = QLatin1StringView ("PyTypeObject");
 
 // numpy
-static inline QString cPyArrayObjectT() { return QStringLiteral("PyArrayObject"); }
+constexpr auto cPyArrayObjectT = QLatin1StringView ("PyArrayObject");
 
-static inline QString sbkCharT() { return QStringLiteral("SbkChar"); }
+constexpr auto sbkCharT = QLatin1StringView ("SbkChar");
 
 #endif // PYTYPENAMES_H
index 3830540cfce3ee2bccc636f3aed60bf010a6f8b3..a1417e5d9e360cf4236ca588152db87dc985205d 100644 (file)
 
 using namespace Qt::StringLiterals;
 
-static const char PARENT_CTOR_HEURISTIC[] = "enable-parent-ctor-heuristic";
-static const char RETURN_VALUE_HEURISTIC[] = "enable-return-value-heuristic";
-static const char DISABLE_VERBOSE_ERROR_MESSAGES[] = "disable-verbose-error-messages";
-static const char USE_ISNULL_AS_NB_BOOL[] = "use-isnull-as-nb-bool";
+static constexpr auto PARENT_CTOR_HEURISTIC = "enable-parent-ctor-heuristic"_L1;
+static constexpr auto RETURN_VALUE_HEURISTIC = "enable-return-value-heuristic"_L1;
+static constexpr auto DISABLE_VERBOSE_ERROR_MESSAGES = "disable-verbose-error-messages"_L1;
+static constexpr auto USE_ISNULL_AS_NB_BOOL = "use-isnull-as-nb-bool"_L1;
 // FIXME PYSIDE 7: Remove USE_ISNULL_AS_NB_NONZERO/USE_OPERATOR_BOOL_AS_NB_NONZERO
-static const char USE_ISNULL_AS_NB_NONZERO[] = "use-isnull-as-nb_nonzero";
-static const char USE_OPERATOR_BOOL_AS_NB_BOOL[] = "use-operator-bool-as-nb-bool";
-static const char USE_OPERATOR_BOOL_AS_NB_NONZERO[] = "use-operator-bool-as-nb-nonzero";
-static const char WRAPPER_DIAGNOSTICS[] = "wrapper-diagnostics";
-static const char NO_IMPLICIT_CONVERSIONS[] = "no-implicit-conversions";
-static const char LEAN_HEADERS[] = "lean-headers";
+static constexpr auto USE_ISNULL_AS_NB_NONZERO = "use-isnull-as-nb_nonzero"_L1;
+static constexpr auto USE_OPERATOR_BOOL_AS_NB_BOOL = "use-operator-bool-as-nb-bool"_L1;
+static constexpr auto USE_OPERATOR_BOOL_AS_NB_NONZERO = "use-operator-bool-as-nb-nonzero"_L1;
+static constexpr auto WRAPPER_DIAGNOSTICS = "wrapper-diagnostics"_L1;
+static constexpr auto NO_IMPLICIT_CONVERSIONS = "no-implicit-conversions"_L1;
+static constexpr auto LEAN_HEADERS = "lean-headers"_L1;
 
-QString CPP_ARG(int i)
+QString CPP_ARG_N(int i)
 {
-    return u"cppArg"_s + QString::number(i);
+    return CPP_ARG + QString::number(i);
 }
 
-static const QString CPP_ARG_REMOVED_PREFIX = u"removed_cppArg"_s;
+constexpr auto CPP_ARG_REMOVED_PREFIX = "removed_cppArg"_L1;
 
 QString CPP_ARG_REMOVED(int i)
 {
     return CPP_ARG_REMOVED_PREFIX + QString::number(i);
 }
 
-const QString CPP_RETURN_VAR = u"cppResult"_s;
-const QString CPP_SELF_VAR = u"cppSelf"_s;
-const QString NULL_PTR = u"nullptr"_s;
-const QString PYTHON_ARG = u"pyArg"_s;
-const QString PYTHON_ARGS = u"pyArgs"_s;
-const QString PYTHON_OVERRIDE_VAR = u"pyOverride"_s;
-const QString PYTHON_RETURN_VAR = u"pyResult"_s;
-const QString PYTHON_TO_CPP_VAR = u"pythonToCpp"_s;
-
-const QString CONV_RULE_OUT_VAR_SUFFIX = u"_out"_s;
-const QString BEGIN_ALLOW_THREADS =
-    u"PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS"_s;
-const QString END_ALLOW_THREADS = u"PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS"_s;
-
-const QString REPR_FUNCTION = u"__repr__"_s;
-
-const QString CPP_ARG0 = u"cppArg0"_s;
 const char *const METHOD_DEF_SENTINEL = "{nullptr, nullptr, 0, nullptr} // Sentinel\n";
 const char *const PYTHON_TO_CPPCONVERSION_STRUCT = "Shiboken::Conversions::PythonToCppConversion";
 
@@ -163,32 +146,32 @@ ShibokenGenerator::~ShibokenGenerator() = default;
 static const QHash<QString, QString> &primitiveTypesCorrespondences()
 {
     static const QHash<QString, QString> result = {
-        {u"bool"_s, pyBoolT()},
-        {u"char"_s, sbkCharT()},
-        {u"signed char"_s, sbkCharT()},
-        {u"unsigned char"_s, sbkCharT()},
-        {intT(), pyLongT()},
-        {u"signed int"_s, pyLongT()},
-        {u"uint"_s, pyLongT()},
-        {u"unsigned int"_s, pyLongT()},
-        {shortT(), pyLongT()},
-        {u"ushort"_s, pyLongT()},
-        {u"signed short"_s, pyLongT()},
-        {u"signed short int"_s, pyLongT()},
-        {unsignedShortT(), pyLongT()},
-        {u"unsigned short int"_s, pyLongT()},
-        {longT(), pyLongT()},
-        {doubleT(), pyFloatT()},
-        {floatT(), pyFloatT()},
-        {u"unsigned long"_s, pyLongT()},
-        {u"signed long"_s, pyLongT()},
-        {u"ulong"_s, pyLongT()},
-        {u"unsigned long int"_s, pyLongT()},
-        {u"long long"_s, pyLongT()},
-        {u"__int64"_s, pyLongT()},
-        {u"unsigned long long"_s, pyLongT()},
-        {u"unsigned __int64"_s, pyLongT()},
-        {u"size_t"_s, pyLongT()}
+        {u"bool"_s, pyBoolT},
+        {u"char"_s, sbkCharT},
+        {u"signed char"_s, sbkCharT},
+        {u"unsigned char"_s, sbkCharT},
+        {intT, pyLongT},
+        {u"signed int"_s, pyLongT},
+        {u"uint"_s, pyLongT},
+        {u"unsigned int"_s, pyLongT},
+        {shortT, pyLongT},
+        {u"ushort"_s, pyLongT},
+        {u"signed short"_s, pyLongT},
+        {u"signed short int"_s, pyLongT},
+        {unsignedShortT, pyLongT},
+        {u"unsigned short int"_s, pyLongT},
+        {longT, pyLongT},
+        {doubleT, pyFloatT},
+        {floatT, pyFloatT},
+        {u"unsigned long"_s, pyLongT},
+        {u"signed long"_s, pyLongT},
+        {u"ulong"_s, pyLongT},
+        {u"unsigned long int"_s, pyLongT},
+        {u"long long"_s, pyLongT},
+        {u"__int64"_s, pyLongT},
+        {u"unsigned long long"_s, pyLongT},
+        {u"unsigned __int64"_s, pyLongT},
+        {u"size_t"_s, pyLongT}
     };
     return result;
 }
@@ -198,18 +181,18 @@ const QHash<QString, QChar> &ShibokenGenerator::formatUnits()
     static const QHash<QString, QChar> result = {
         {u"char"_s, u'b'},
         {u"unsigned char"_s, u'B'},
-        {intT(), u'i'},
+        {intT, u'i'},
         {u"unsigned int"_s, u'I'},
-        {shortT(), u'h'},
-        {unsignedShortT(), u'H'},
-        {longT(), u'l'},
-        {unsignedLongLongT(), u'k'},
-        {longLongT(), u'L'},
+        {shortT, u'h'},
+        {unsignedShortT, u'H'},
+        {longT, u'l'},
+        {unsignedLongLongT, u'k'},
+        {longLongT, u'L'},
         {u"__int64"_s, u'L'},
-        {unsignedLongLongT(), u'K'},
+        {unsignedLongLongT, u'K'},
         {u"unsigned __int64"_s, u'K'},
-        {doubleT(), u'd'},
-        {floatT(), u'f'},
+        {doubleT, u'd'},
+        {floatT, u'f'},
     };
     return result;
 }
@@ -240,6 +223,15 @@ bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClassCPtr &me
             && wrapper.testFlag(AbstractMetaClass::CppProtectedHackWrapper));
 }
 
+bool ShibokenGenerator::shouldGenerateMetaObjectFunctions(const AbstractMetaClassCPtr &metaClass)
+{
+    return usePySideExtensions()
+        && (!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
+           && !metaClass->typeEntry()->typeFlags()
+                  .testFlag(ComplexTypeEntry::DisableQtMetaObjectFunctions)
+        && isQObject(metaClass);
+}
+
 ShibokenGenerator::FunctionGeneration ShibokenGenerator::functionGeneration(
     const AbstractMetaFunctionCPtr &func)
 {
@@ -284,7 +276,7 @@ ShibokenGenerator::FunctionGeneration ShibokenGenerator::functionGeneration(
     // Check on virtuals (including operators).
     const bool isAbstract = func->isAbstract();
     if (!(isAbstract || func->isVirtual())
-        || func->attributes().testFlag(AbstractMetaFunction::FinalCppMethod)
+        || func->cppAttributes().testFlag(FunctionAttribute::Final)
         || func->isModifiedFinal()) {
         return result;
     }
@@ -343,7 +335,7 @@ QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClassCPtr &meta
             fullClassName.prepend(enclosing->name() + u'.');
         enclosing = enclosing->enclosingClass();
     }
-    fullClassName.prepend(packageName() + u'.');
+    fullClassName.prepend(metaClass->typeEntry()->targetLangPackage() + u'.');
     return fullClassName;
 }
 
@@ -471,13 +463,13 @@ QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClassCP
 QString ShibokenGenerator::cpythonGetterFunctionName(const QString &name,
                                                      const AbstractMetaClassCPtr &enclosingClass)
 {
-    return cpythonBaseName(enclosingClass) + QStringLiteral("_get_") + name;
+    return cpythonBaseName(enclosingClass) + "_get_"_L1 + name;
 }
 
 QString ShibokenGenerator::cpythonSetterFunctionName(const QString &name,
                                                      const AbstractMetaClassCPtr &enclosingClass)
 {
-    return cpythonBaseName(enclosingClass) + QStringLiteral("_set_") + name;
+    return cpythonBaseName(enclosingClass) + "_set_"_L1 + name;
 }
 
 QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField &metaField)
@@ -639,7 +631,7 @@ QString ShibokenGenerator::containerCpythonBaseName(const ContainerTypeEntryCPtr
     default:
         Q_ASSERT(false);
     }
-    return cPySequenceT();
+    return cPySequenceT;
 }
 
 QString ShibokenGenerator::cpythonBaseName(const TypeEntryCPtr &type)
@@ -659,7 +651,7 @@ QString ShibokenGenerator::cpythonBaseName(const TypeEntryCPtr &type)
         const auto ctype = std::static_pointer_cast<const ContainerTypeEntry>(type);
         baseName = containerCpythonBaseName(ctype);
     } else {
-        baseName = cPyObjectT();
+        baseName = cPyObjectT;
     }
     return baseName.replace(u"::"_s, u"_"_s);
 }
@@ -674,12 +666,6 @@ QString ShibokenGenerator::cpythonTypeName(const TypeEntryCPtr &type)
     return cpythonBaseName(type) + u"_TypeF()"_s;
 }
 
-QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntryCPtr &type)
-{
-    return cppApiVariableName(type->targetLangPackage()) + u'['
-            + getTypeIndexVariableName(type) + u']';
-}
-
 QString ShibokenGenerator::converterObject(const AbstractMetaType &type)
 {
     if (type.isCString())
@@ -688,7 +674,7 @@ QString ShibokenGenerator::converterObject(const AbstractMetaType &type)
         return u"Shiboken::Conversions::PrimitiveTypeConverter<void *>()"_s;
     const AbstractMetaTypeList nestedArrayTypes = type.nestedArrayTypes();
     if (!nestedArrayTypes.isEmpty() && nestedArrayTypes.constLast().isCppPrimitive()) {
-        return QStringLiteral("Shiboken::Conversions::ArrayTypeConverter<")
+        return "Shiboken::Conversions::ArrayTypeConverter<"_L1
             + nestedArrayTypes.constLast().minimalSignature()
             + u">("_s + QString::number(nestedArrayTypes.size())
             + u')';
@@ -735,13 +721,29 @@ QString ShibokenGenerator::converterObject(const TypeEntryCPtr &type)
            + u'[' + getTypeIndexVariableName(type) + u']';
 }
 
-QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType &type)
+QString ShibokenGenerator::cpythonTypeNameExtSet(const TypeEntryCPtr &type)
+{
+    return cppApiVariableName(type->targetLangPackage()) + u'['
+            + getTypeIndexVariableName(type) + "].type"_L1;
+}
+
+QString ShibokenGenerator::cpythonTypeNameExtSet(const AbstractMetaType &type)
 {
     return cppApiVariableName(type.typeEntry()->targetLangPackage()) + u'['
-           + getTypeIndexVariableName(type) + u']';
+           + getTypeIndexVariableName(type) + "].type"_L1;
 }
 
-static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); }
+QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntryCPtr &type)
+{
+    return "Shiboken::Module::get("_L1 + cppApiVariableName(type->targetLangPackage())
+            + u'[' + getTypeIndexVariableName(type) + "])"_L1;
+}
+
+QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType &type)
+{
+    return u"Shiboken::Module::get("_s + cppApiVariableName(type.typeEntry()->targetLangPackage())
+            + u'[' + getTypeIndexVariableName(type) + "])"_L1;
+}
 
 QString ShibokenGenerator::fixedCppTypeName(const TargetToNativeConversion &toNative)
 {
@@ -791,7 +793,7 @@ QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction
     QString op = Generator::pythonOperatorFunctionName(func->originalName());
     if (op.isEmpty()) {
         qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func.get());
-        return unknownOperator();
+        return "__UNKNOWN_OPERATOR__"_L1;
     }
     if (func->arguments().isEmpty()) {
         if (op == u"__sub__")
@@ -808,8 +810,8 @@ QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction
 
 bool ShibokenGenerator::isNumber(const QString &cpythonApiName)
 {
-    return cpythonApiName == pyFloatT() || cpythonApiName == pyLongT()
-       || cpythonApiName == pyBoolT();
+    return cpythonApiName == pyFloatT || cpythonApiName == pyLongT
+       || cpythonApiName == pyBoolT;
 }
 
 static std::optional<TypeSystem::CPythonType>
@@ -856,7 +858,7 @@ bool ShibokenGenerator::isPyInt(const TypeEntryCPtr &type)
     if (!cPythonTypeOpt.has_value()) {
         const auto &mapping = primitiveTypesCorrespondences();
         const auto it = mapping.constFind(pte->name());
-        return it != mapping.cend() && it.value() ==  pyLongT();
+        return it != mapping.cend() && it.value() ==  pyLongT;
     }
     return cPythonTypeOpt.value() == TypeSystem::CPythonType::Integer;
 }
@@ -1045,8 +1047,8 @@ QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType
             + (type.isPointer() ? u"Pointer"_s : u"Copy"_s)
             + u'(' + cpythonTypeNameExt(type) + u", "_s;
     }
-    return QStringLiteral("Shiboken::Conversions::pythonToCppCopy(%1, ")
-              .arg(converterObject(type));
+    return "Shiboken::Conversions::pythonToCppCopy("_L1
+           + converterObject(type) + ", "_L1;
 }
 
 QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType &type)
@@ -1145,6 +1147,10 @@ void ShibokenGenerator::writeFunctionArguments(TextStream &s,
                                                Options options) const
 {
     int argUsed = 0;
+    if (func->isUserAddedPythonOverride()) {
+        s << "Shiboken::GilState &gil, PyObject *" << PYTHON_OVERRIDE_VAR;
+        argUsed += 2;
+    }
     for (const auto &arg : func->arguments()) {
         if (options.testFlag(Generator::SkipRemovedArguments) && arg.isModifiedRemoved())
             continue;
@@ -1181,6 +1187,8 @@ QString ShibokenGenerator::functionSignature(const AbstractMetaFunctionCPtr &fun
 {
     StringStream s(TextStream::Language::Cpp);
     // The actual function
+    if (!options.testFlag(Option::SkipDefaultValues) && func->isStatic()) // Declaration
+        s << "static ";
     if (func->isEmptyFunction() || func->needsReturnType())
         s << functionReturnType(func, options) << ' ';
     else
@@ -1383,7 +1391,7 @@ ShibokenGenerator::ArgumentVarReplacementList
                 } else {
                     argValue = hasConversionRule
                                ? arg.name() + CONV_RULE_OUT_VAR_SUFFIX
-                               : CPP_ARG(argPos);
+                               : CPP_ARG_N(argPos);
                     const auto generatorArg = GeneratorArgument::fromMetaType(type);
                     AbstractMetaType::applyDereference(&argValue, generatorArg.indirections);
                 }
@@ -1425,7 +1433,7 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
 
 static void replacePyArg0(TypeSystem::Language language, QString *code)
 {
-    static const QString pyArg0 = u"%PYARG_0"_s;
+    static constexpr auto pyArg0 = "%PYARG_0"_L1;
 
     if (!code->contains(pyArg0))
         return;
@@ -1464,13 +1472,13 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
     // Replace %PYARG_# variables.
     replacePyArg0(language, &code);
 
-    static const QRegularExpression pyArgsRegex(QStringLiteral("%PYARG_(\\d+)"));
+    static const QRegularExpression pyArgsRegex("%PYARG_(\\d+)"_L1);
     Q_ASSERT(pyArgsRegex.isValid());
     if (language == TypeSystem::TargetLangCode) {
         if (usePyArgs) {
             code.replace(pyArgsRegex, PYTHON_ARGS + u"[\\1-1]"_s);
         } else {
-            static const QRegularExpression pyArgsRegexCheck(QStringLiteral("%PYARG_([2-9]+)"));
+            static const QRegularExpression pyArgsRegexCheck("%PYARG_([2-9]+)"_L1);
             Q_ASSERT(pyArgsRegexCheck.isValid());
             const QRegularExpressionMatch match = pyArgsRegexCheck.match(code);
             if (match.hasMatch()) {
@@ -1483,7 +1491,7 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
     } else {
         // Replaces the simplest case of attribution to a
         // Python argument on the binding virtual method.
-        static const QRegularExpression pyArgsAttributionRegex(QStringLiteral("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"));
+        static const QRegularExpression pyArgsAttributionRegex("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"_L1);
         Q_ASSERT(pyArgsAttributionRegex.isValid());
         code.replace(pyArgsAttributionRegex, u"PyTuple_SET_ITEM("_s
                      + PYTHON_ARGS + u".object(), \\1-1, \\2)"_s);
@@ -1500,7 +1508,7 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
         code.replace(argTypeVar, argTypeVal);
     }
 
-    static const QRegularExpression cppArgTypeRegexCheck(QStringLiteral("%ARG(\\d+)_TYPE"));
+    static const QRegularExpression cppArgTypeRegexCheck("%ARG(\\d+)_TYPE"_L1);
     Q_ASSERT(cppArgTypeRegexCheck.isValid());
     QRegularExpressionMatchIterator rit = cppArgTypeRegexCheck.globalMatch(code);
     while (rit.hasNext()) {
@@ -1642,8 +1650,8 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
 
         if (isProtected) {
             code.replace(u"%TYPE::%FUNCTION_NAME"_s,
-                         QStringLiteral("%1::%2_protected")
-                         .arg(wrapperName(func->ownerClass()), func->originalName()));
+                         wrapperName(func->ownerClass()) + "::"_L1
+                                     + func->originalName() + "_protected"_L1);
             code.replace(u"%FUNCTION_NAME"_s,
                          func->originalName() + u"_protected"_s);
         }
@@ -1665,7 +1673,7 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
 // and false if it is a variable.
 static bool isVariable(const QString &code)
 {
-    static const QRegularExpression expr(QStringLiteral("^\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*$"));
+    static const QRegularExpression expr("^\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*$"_L1);
     Q_ASSERT(expr.isValid());
     return expr.match(code.trimmed()).hasMatch();
 }
@@ -1777,7 +1785,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
             case TypeSystemCheckFunction:
                 conversion = cpythonCheckFunction(conversionType);
                 if (conversionType.typeEntry()->isPrimitive()
-                    && (conversionType.typeEntry()->name() == cPyObjectT()
+                    && (conversionType.typeEntry()->name() == cPyObjectT
                         || !conversion.endsWith(u' '))) {
                     conversion += u'(';
                     break;
@@ -1853,7 +1861,7 @@ ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(
                                           FunctionQueryOption::GetAttroFunction)) {
             result |= AttroCheckFlag::GetattroUser;
         }
-        if (usePySideExtensions() && metaClass->qualifiedCppName() == qObjectT())
+        if (usePySideExtensions() && metaClass->qualifiedCppName() == qObjectT)
             result |= AttroCheckFlag::SetattroQObject;
         if (useOverrideCaching(metaClass))
             result |= AttroCheckFlag::SetattroMethodOverride;
@@ -1934,17 +1942,17 @@ AbstractMetaClassCPtr
 
 QString ShibokenGenerator::getModuleHeaderFileBaseName(const QString &moduleName)
 {
-    return moduleCppPrefix(moduleName).toLower() + QStringLiteral("_python");
+    return moduleCppPrefix(moduleName).toLower() + "_python"_L1;
 }
 
 QString ShibokenGenerator::getModuleHeaderFileName(const QString &moduleName)
 {
-    return getModuleHeaderFileBaseName(moduleName) + QStringLiteral(".h");
+    return getModuleHeaderFileBaseName(moduleName) + ".h"_L1;
 }
 
 QString ShibokenGenerator::getPrivateModuleHeaderFileName(const QString &moduleName)
 {
-    return getModuleHeaderFileBaseName(moduleName) + QStringLiteral("_p.h");
+    return getModuleHeaderFileBaseName(moduleName) + "_p.h"_L1;
 }
 
 IncludeGroupList ShibokenGenerator::classIncludes(const AbstractMetaClassCPtr &metaClass) const
@@ -2253,8 +2261,9 @@ ShibokenGenerator::filterGroupedOperatorFunctions(const AbstractMetaClassCPtr &m
 
 static bool hidesBaseClassFunctions(const AbstractMetaFunctionCPtr &f)
 {
-    return 0 == (f->attributes()
-                 & (AbstractMetaFunction::OverriddenCppMethod | AbstractMetaFunction::FinalCppMethod));
+    auto attributes = f->cppAttributes();
+    return !attributes.testFlag(FunctionAttribute::Override)
+        && !attributes.testFlag(FunctionAttribute::Final);
 }
 
 void ShibokenGenerator::getInheritedOverloads(const AbstractMetaClassCPtr &scope,
@@ -2330,25 +2339,25 @@ void ShibokenGenerator::getInheritedOverloads(const AbstractMetaClassCPtr &scope
 QList<OptionDescription> ShibokenGenerator::options()
 {
     return {
-        {QLatin1StringView(DISABLE_VERBOSE_ERROR_MESSAGES),
+        {DISABLE_VERBOSE_ERROR_MESSAGES,
          u"Disable verbose error messages. Turn the python code hard to debug\n"
           "but safe few kB on the generated bindings."_s},
-        {QLatin1StringView(PARENT_CTOR_HEURISTIC),
+        {PARENT_CTOR_HEURISTIC,
          u"Enable heuristics to detect parent relationship on constructors."_s},
-        {QLatin1StringView(RETURN_VALUE_HEURISTIC),
+        {RETURN_VALUE_HEURISTIC,
          u"Enable heuristics to detect parent relationship on return values\n"
           "(USE WITH CAUTION!)"_s},
-        {QLatin1StringView(USE_ISNULL_AS_NB_BOOL),
+        {USE_ISNULL_AS_NB_BOOL,
          u"If a class have an isNull() const method, it will be used to compute\n"
           "the value of boolean casts"_s},
-        {QLatin1StringView(LEAN_HEADERS),
+        {LEAN_HEADERS,
          u"Forward declare classes in module headers"_s},
-        {QLatin1StringView(USE_OPERATOR_BOOL_AS_NB_BOOL),
+        {USE_OPERATOR_BOOL_AS_NB_BOOL,
          u"If a class has an operator bool, it will be used to compute\n"
           "the value of boolean casts"_s},
-        {QLatin1StringView(NO_IMPLICIT_CONVERSIONS),
+        {NO_IMPLICIT_CONVERSIONS,
          u"Do not generate implicit_conversions for function arguments."_s},
-        {QLatin1StringView(WRAPPER_DIAGNOSTICS),
+        {WRAPPER_DIAGNOSTICS,
          u"Generate diagnostic code around wrappers"_s}
     };
 }
@@ -2368,27 +2377,25 @@ bool ShibokenGeneratorOptionsParser::handleBoolOption(const QString &key, Option
 {
     if (source == OptionSource::CommandLineSingleDash)
         return false;
-    if (key == QLatin1StringView(PARENT_CTOR_HEURISTIC))
+    if (key == PARENT_CTOR_HEURISTIC)
         return (m_options->useCtorHeuristic = true);
-    if (key == QLatin1StringView(RETURN_VALUE_HEURISTIC))
+    if (key == RETURN_VALUE_HEURISTIC)
         return (m_options->userReturnValueHeuristic = true);
-    if (key == QLatin1StringView(DISABLE_VERBOSE_ERROR_MESSAGES))
+    if (key == DISABLE_VERBOSE_ERROR_MESSAGES)
         return (m_options->verboseErrorMessagesDisabled = true);
-    if (key == QLatin1StringView(USE_ISNULL_AS_NB_BOOL)
-        || key == QLatin1StringView(USE_ISNULL_AS_NB_NONZERO)) {
+    if (key == USE_ISNULL_AS_NB_BOOL || key == USE_ISNULL_AS_NB_NONZERO) {
         return (m_options->useIsNullAsNbBool = true);
     }
-    if (key == QLatin1StringView(LEAN_HEADERS))
+    if (key == LEAN_HEADERS)
         return (m_options->leanHeaders= true);
-    if (key == QLatin1StringView(USE_OPERATOR_BOOL_AS_NB_BOOL)
-        || key == QLatin1StringView(USE_OPERATOR_BOOL_AS_NB_NONZERO)) {
+    if (key == USE_OPERATOR_BOOL_AS_NB_BOOL || key == USE_OPERATOR_BOOL_AS_NB_NONZERO) {
         return (m_options->useOperatorBoolAsNbBool = true);
     }
-    if (key == QLatin1StringView(NO_IMPLICIT_CONVERSIONS)) {
+    if (key == NO_IMPLICIT_CONVERSIONS) {
         m_options->generateImplicitConversions = false;
         return true;
     }
-    if (key == QLatin1StringView(WRAPPER_DIAGNOSTICS))
+    if (key == WRAPPER_DIAGNOSTICS)
         return (m_options->wrapperDiagnostics = true);
     return false;
 }
@@ -2440,19 +2447,24 @@ QString ShibokenGenerator::moduleCppPrefix(const QString &moduleName)
     return result;
 }
 
+QString ShibokenGenerator::cppApiVariableNameOld(const QString &moduleName)
+{
+    return "Sbk"_L1 + moduleCppPrefix(moduleName) + "Types"_L1;
+}
+
 QString ShibokenGenerator::cppApiVariableName(const QString &moduleName)
 {
-    return u"Sbk"_s + moduleCppPrefix(moduleName) + u"Types"_s;
+    return "Sbk"_L1 + moduleCppPrefix(moduleName) + "TypeStructs"_L1;
 }
 
 QString ShibokenGenerator::pythonModuleObjectName(const QString &moduleName)
 {
-    return u"Sbk"_s + moduleCppPrefix(moduleName) + u"ModuleObject"_s;
+    return "Sbk"_L1 + moduleCppPrefix(moduleName) + "ModuleObject"_L1;
 }
 
 QString ShibokenGenerator::convertersVariableName(const QString &moduleName)
 {
-    QString result = cppApiVariableName(moduleName);
+    QString result = cppApiVariableNameOld(moduleName);
     result.chop(1);
     result.append(u"Converters"_s);
     return result;
@@ -2460,11 +2472,11 @@ QString ShibokenGenerator::convertersVariableName(const QString &moduleName)
 
 static QString processInstantiationsVariableName(const AbstractMetaType &type)
 {
-    QString res = u'_' + _fixedCppTypeName(type.typeEntry()->qualifiedCppName()).toUpper();
+    QString res = u'_' + _fixedCppTypeName(type.typeEntry()->qualifiedCppName());
     for (const auto &instantiation : type.instantiations()) {
         res += instantiation.isContainer()
                ? processInstantiationsVariableName(instantiation)
-               : u'_' + _fixedCppTypeName(instantiation.cppSignature()).toUpper();
+               : u'_' + _fixedCppTypeName(instantiation.cppSignature());
     }
     return res;
 }
@@ -2473,7 +2485,7 @@ static void appendIndexSuffix(QString *s)
 {
     if (!s->endsWith(u'_'))
         s->append(u'_');
-    s->append(QStringLiteral("IDX"));
+    s->append("IDX"_L1);
 }
 
 QString
@@ -2482,7 +2494,7 @@ QString
     const auto templateBaseClass = metaClass->templateBaseClass();
     Q_ASSERT(templateBaseClass);
     QString result = u"SBK_"_s
-        + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper();
+        + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName());
     for (const auto &instantiation : metaClass->templateBaseClassInstantiations())
         result += processInstantiationsVariableName(instantiation);
     appendIndexSuffix(&result);
@@ -2504,7 +2516,7 @@ QString ShibokenGenerator::getTypeIndexVariableName(TypeEntryCPtr type)
         const int dot = package.lastIndexOf(u'.');
         result += QStringView{package}.right(package.size() - (dot + 1));
     }
-    result += _fixedCppTypeName(type->qualifiedCppName()).toUpper();
+    result += _fixedCppTypeName(type->qualifiedCppName());
     appendIndexSuffix(&result);
     return result;
 }
@@ -2512,12 +2524,45 @@ QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType &type
 {
     QString result = u"SBK"_s;
     if (type.typeEntry()->isContainer())
-        result += u'_' + moduleName().toUpper();
+        result += u'_' + moduleName();
     result += processInstantiationsVariableName(type);
     appendIndexSuffix(&result);
     return result;
 }
 
+void collectfromTypeEntry(TypeEntryCPtr entry, QStringList &typeNames)
+{
+    if (entry->shouldGenerate()) {
+        typeNames[entry->sbkIndex()] = entry->qualifiedTargetLangName();
+        if (entry->isEnum()) {
+            auto ete = std::static_pointer_cast<const EnumTypeEntry>(entry);
+            if (ete->flags()) {
+                auto entry = ete->flags();
+                typeNames[entry->sbkIndex()] = entry->qualifiedTargetLangName();
+            }
+        }
+    }
+}
+
+void ShibokenGenerator::collectFullTypeNamesArray(QStringList &typeNames)
+{
+    for (const auto &metaClass : api().classes()) {
+        collectfromTypeEntry(metaClass->typeEntry(), typeNames);
+
+        for (const AbstractMetaEnum &metaEnum : metaClass->enums())
+            collectfromTypeEntry(metaEnum.typeEntry(), typeNames);
+
+        int smartPointerCountIndex = getMaxTypeIndex();
+        for (const auto &smp : api().instantiatedSmartPointers()) {
+            auto entry = smp.type.typeEntry();
+            typeNames[smartPointerCountIndex] = entry->qualifiedTargetLangName();
+            ++smartPointerCountIndex;
+        }
+    }
+    for (const AbstractMetaEnum &metaEnum : api().globalEnums())
+        collectfromTypeEntry(metaEnum.typeEntry(), typeNames);
+}
+
 bool ShibokenGenerator::verboseErrorMessagesDisabled()
 {
     return m_options.verboseErrorMessagesDisabled;
index 25eb7854169e4cf41185ba541970d8ce9162aceb..22ee73fa2d64fcb9c9a3fecdce25aabdebea89aa 100644 (file)
@@ -203,6 +203,8 @@ protected:
     /// instead of only a Python wrapper.
     static bool shouldGenerateCppWrapper(const AbstractMetaClassCPtr &metaClass);
 
+    static bool shouldGenerateMetaObjectFunctions(const AbstractMetaClassCPtr &metaClass);
+
     /// Returns which functions need to be generated into the wrapper class
     static FunctionGeneration functionGeneration(const AbstractMetaFunctionCPtr &func);
 
@@ -250,8 +252,10 @@ protected:
     static QString cpythonBaseName(const AbstractMetaType &type);
     static QString cpythonTypeName(const AbstractMetaClassCPtr &metaClass);
     static QString cpythonTypeName(const TypeEntryCPtr &type);
+    static QString cpythonTypeNameExtSet(const TypeEntryCPtr &type);
+    static QString cpythonTypeNameExtSet(const AbstractMetaType &type);
     static QString cpythonTypeNameExt(const TypeEntryCPtr &type);
-    static QString cpythonTypeNameExt(const AbstractMetaType &type) ;
+    static QString cpythonTypeNameExt(const AbstractMetaType &type);
     static QString cpythonCheckFunction(TypeEntryCPtr type);
     static QString cpythonCheckFunction(AbstractMetaType metaType);
     static QString cpythonIsConvertibleFunction(const TypeEntryCPtr &type);
@@ -276,8 +280,8 @@ protected:
     static QString cpythonSetterFunctionName(const QPropertySpec &property,
                                              const AbstractMetaClassCPtr &metaClass);
     static QString cpythonWrapperCPtr(const AbstractMetaClassCPtr &metaClass,
-                                      const QString &argName = QStringLiteral("self"));
-     static QString cpythonWrapperCPtr(const AbstractMetaType &metaType,
+                                      const QString &argName = QLatin1StringView("self"));
+    static QString cpythonWrapperCPtr(const AbstractMetaType &metaType,
                                       const QString &argName);
     static QString cpythonWrapperCPtr(const TypeEntryCPtr &type, const QString &argName);
 
@@ -310,6 +314,7 @@ protected:
     static bool useOperatorBoolAsNbBool();
     /// Generate implicit conversions of function arguments
     static bool generateImplicitConversions();
+    static QString cppApiVariableNameOld(const QString &moduleName = {});
     static QString cppApiVariableName(const QString &moduleName = QString());
     static QString pythonModuleObjectName(const QString &moduleName = QString());
     static QString convertersVariableName(const QString &moduleName = QString());
@@ -321,6 +326,9 @@ protected:
     static QString getTypeIndexVariableName(TypeEntryCPtr type);
     static QString getTypeIndexVariableName(const AbstractMetaType &type) ;
 
+    /// Collect all type names as an array for initializing the type/name struct.
+    void collectFullTypeNamesArray(QStringList &typeNames);
+
     /// Returns true if the user don't want verbose error messages on the generated bindings.
     static bool verboseErrorMessagesDisabled();
 
diff --git a/sources/shiboken6/generators/shiboken/shiboken.cpp b/sources/shiboken6/generators/shiboken/shiboken.cpp
deleted file mode 100644 (file)
index 193b8e9..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "cppgenerator.h"
-#include "headergenerator.h"
-
-EXPORT_GENERATOR_PLUGIN(new CppGenerator << new HeaderGenerator)
index 4638ca6f96a74f8f9f0f0f160e35c71546532698..b5bbb498a38b8fc25b1895ab1636c62ccdf1f205 100644 (file)
@@ -66,6 +66,7 @@ debugfreehook.cpp debugfreehook.h
 gilstate.cpp gilstate.h
 helper.cpp helper.h
 pep384impl.cpp pep384impl.h
+pyobjectholder.h
 sbkarrayconverter.cpp sbkarrayconverter.h sbkarrayconverter_p.h
 sbkcontainer.cpp sbkcontainer.h
 sbkconverter.cpp sbkconverter.h sbkconverter_p.h
@@ -158,6 +159,7 @@ install(FILES
         bindingmanager.h
         gilstate.h
         helper.h
+        pyobjectholder.h
         sbkarrayconverter.h
         sbkcontainer.h
         sbkconverter.h
@@ -180,6 +182,7 @@ install(FILES
         sbkpython.h
         sbkwindows.h
         pep384impl.h
+        pep384ext.h
         voidptr.h
         bufferprocs_py37.h
         "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h"
index f1b48fbd4495c02ca73f751047d655581a2e0f81..62a8584e1b8ca60cbd0d1092b22e06a005ca99ef 100644 (file)
@@ -5,7 +5,6 @@
 #define AUTODECREF_H
 
 #include "sbkpython.h"
-#include "basewrapper.h"
 
 #include <utility>
 
@@ -16,13 +15,13 @@ namespace Shiboken
 /**
  *  AutoDecRef holds a PyObject pointer and decrement its reference counter when destroyed.
  */
-struct LIBSHIBOKEN_API AutoDecRef
+struct AutoDecRef
 {
 public:
     AutoDecRef(const AutoDecRef &) = delete;
     AutoDecRef(AutoDecRef &&o) noexcept : m_pyObj{std::exchange(o.m_pyObj, nullptr)} {}
     AutoDecRef &operator=(const AutoDecRef &) = delete;
-    AutoDecRef &operator=(AutoDecRef &&o)
+    AutoDecRef &operator=(AutoDecRef &&o) noexcept
     {
         m_pyObj = std::exchange(o.m_pyObj, nullptr);
         return *this;
@@ -44,10 +43,10 @@ public:
         Py_XDECREF(m_pyObj);
     }
 
-    inline bool isNull() const { return m_pyObj == nullptr; }
+    [[nodiscard]] bool isNull() const { return m_pyObj == nullptr; }
     /// Returns the pointer of the Python object being held.
-    inline PyObject *object() { return m_pyObj; }
-    inline operator PyObject *() { return m_pyObj; }
+    [[nodiscard]] PyObject *object() const { return m_pyObj; }
+    [[nodiscard]] operator PyObject *() const { return m_pyObj; }
 #ifndef Py_LIMITED_API
     [[deprecated]] inline operator PyTupleObject *()
     { return reinterpret_cast<PyTupleObject *>(m_pyObj); }
@@ -86,4 +85,3 @@ private:
 } // namespace Shiboken
 
 #endif // AUTODECREF_H
-
index 70e1e2f45110bb94d1ebf8e0a883f5e39f13c253..ffa73394ff722e080a7c19140d350a8e3d8c2039 100644 (file)
@@ -5,10 +5,12 @@
 #include "basewrapper_p.h"
 #include "bindingmanager.h"
 #include "helper.h"
+#include "pep384ext.h"
 #include "sbkconverter.h"
 #include "sbkenum.h"
 #include "sbkerrors.h"
 #include "sbkfeature_base.h"
+#include "sbkmodule.h"
 #include "sbkstring.h"
 #include "sbkstaticstrings.h"
 #include "sbkstaticstrings_p.h"
@@ -25,7 +27,9 @@
 #include "signature_p.h"
 #include "voidptr.h"
 
+#include <string>
 #include <iostream>
+#include <sstream>
 
 #if defined(__APPLE__)
 #include <dlfcn.h>
@@ -55,7 +59,7 @@ void Sbk_object_dealloc(PyObject *self)
         // This was not needed before Python 3.8 (Python issue 35810)
         Py_DECREF(Py_TYPE(self));
     }
-    Py_TYPE(self)->tp_free(self);
+    PepExt_TypeCallFree(self);
 }
 
 static void SbkObjectType_tp_dealloc(PyTypeObject *pyType);
@@ -152,11 +156,21 @@ static PyTypeObject *createObjectTypeType()
         "1:Shiboken.ObjectType",
         static_cast<int>(PyType_Type.tp_basicsize) + 1,           // see above
         0, // sizeof(PyMemberDef), not for PyPy without a __len__ defined
-        Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+        Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_TYPE_SUBCLASS,
+        SbkObjectType_Type_slots,
+    };
+
+    PyType_Spec SbkObjectType_Type_spec_312 = {
+        "1:Shiboken.ObjectType",
+        -long(sizeof(SbkObjectTypePrivate)),
+        0, // sizeof(PyMemberDef), not for PyPy without a __len__ defined
+        Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_TYPE_SUBCLASS,
         SbkObjectType_Type_slots,
     };
 
-    return SbkType_FromSpec(&SbkObjectType_Type_spec);
+    return SbkType_FromSpec(_PepRuntimeVersion() >= 0x030C00 ?
+                            &SbkObjectType_Type_spec_312 :
+                            &SbkObjectType_Type_spec);
 }
 
 PyTypeObject *SbkObjectType_TypeF(void)
@@ -198,10 +212,8 @@ static int SbkObject_tp_traverse(PyObject *self, visitproc visit, void *arg)
     if (sbkSelf->ob_dict)
         Py_VISIT(sbkSelf->ob_dict);
 
-#if PY_VERSION_HEX >= 0x03090000
     // This was not needed before Python 3.9 (Python issue 35810 and 40217)
     Py_VISIT(Py_TYPE(self));
-#endif
     return 0;
 }
 
@@ -249,12 +261,13 @@ static PyTypeObject *createObjectType()
     //              But before 3.12 is the minimum version, we cannot use the new
     //              function, although we would need this for 3.12 :-D
     //              We do a special patching here that is triggered through Py_None.
-    return SbkType_FromSpec_BMDWB(&SbkObject_Type_spec,
-                                  Py_None,     // bases, special flag!
-                                  SbkObjectType_TypeF(),
-                                  offsetof(SbkObject, ob_dict),
-                                  offsetof(SbkObject, weakreflist),
-                                  nullptr);    // bufferprocs
+    auto *type = SbkType_FromSpec_BMDWB(&SbkObject_Type_spec,
+                                        Py_None,     // bases, spectial flag!
+                                        SbkObjectType_TypeF(),
+                                        offsetof(SbkObject, ob_dict),
+                                        offsetof(SbkObject, weakreflist),
+                                        nullptr);    // bufferprocs
+    return type;
 }
 
 PyTypeObject *SbkObject_TypeF(void)
@@ -509,7 +522,7 @@ static PyTypeObject *SbkObjectType_tp_new(PyTypeObject *metatype, PyObject *args
 
     for (int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) {
         PyObject *baseType = PyTuple_GET_ITEM(pyBases, i);
-        if (reinterpret_cast<PyTypeObject *>(baseType)->tp_new == SbkDummyNew) {
+        if (PepExt_Type_GetNewSlot(reinterpret_cast<PyTypeObject *>(baseType)) == SbkDummyNew) {
             // PYSIDE-595: A base class does not allow inheritance.
             return reinterpret_cast<PyTypeObject *>(SbkDummyNew(metatype, args, kwds));
         }
@@ -661,10 +674,8 @@ PyObject *FallbackRichCompare(PyObject *self, PyObject *other, int op)
 
 bool SbkObjectType_Check(PyTypeObject *type)
 {
-    static auto *obMeta = reinterpret_cast<PyObject *>(SbkObjectType_TypeF());
-    auto *obType = reinterpret_cast<PyObject *>(type);
-    return obMeta == reinterpret_cast<PyObject *>(Py_TYPE(obType))
-           || PyObject_IsInstance(obType, obMeta);
+    static auto *meta = SbkObjectType_TypeF();
+    return Py_TYPE(type) == meta || PyType_IsSubtype(Py_TYPE(type), meta);
 }
 
 } //extern "C"
@@ -739,6 +750,19 @@ bool DtorAccumulatorVisitor::visit(PyTypeObject *node)
 
 void _initMainThreadId(); // helper.cpp
 
+static std::string msgFailedToInitializeType(const char *description)
+{
+    std::ostringstream stream;
+    stream << "[libshiboken] Failed to initialize " << description;
+    if (auto *error = PepErr_GetRaisedException()) {
+        if (auto *str = PyObject_Str(error))
+            stream << ": " << Shiboken::String::toCString(str);
+        Py_DECREF(error);
+    }
+    stream << '.';
+    return stream.str();
+}
+
 namespace Conversions { void init(); }
 
 void init()
@@ -754,11 +778,13 @@ void init()
     //Init private data
     Pep384_Init();
 
-    if (PyType_Ready(SbkObjectType_TypeF()) < 0)
-        Py_FatalError("[libshiboken] Failed to initialize Shiboken.BaseWrapperType metatype.");
+    auto *type = SbkObjectType_TypeF();
+    if (type == nullptr || PyType_Ready(type) < 0)
+        Py_FatalError(msgFailedToInitializeType("Shiboken.BaseWrapperType metatype").c_str());
 
-    if (PyType_Ready(SbkObject_TypeF()) < 0)
-        Py_FatalError("[libshiboken] Failed to initialize Shiboken.BaseWrapper type.");
+    type = SbkObject_TypeF();
+    if (type == nullptr || PyType_Ready(type) < 0)
+        Py_FatalError(msgFailedToInitializeType("Shiboken.BaseWrapper type").c_str());
 
     VoidPtr::init();
 
@@ -959,24 +985,19 @@ introduceWrapperType(PyObject *enclosingObject,
                      const char *originalName,
                      PyType_Spec *typeSpec,
                      ObjectDestructor cppObjDtor,
-                     PyTypeObject *baseType,
-                     PyObject *baseTypes,
+                     PyObject *bases,
                      unsigned wrapperFlags)
 {
-    auto *base = baseType ? baseType : SbkObject_TypeF();
-    typeSpec->slots[0].pfunc = reinterpret_cast<void *>(base);
-    auto *bases = baseTypes ? baseTypes : PyTuple_Pack(1, base);
+    assert(PySequence_Fast_GET_SIZE(bases) > 0);
+    typeSpec->slots[0].pfunc = PySequence_Fast_GET_ITEM(bases, 0);
 
     auto *type = SbkType_FromSpecBasesMeta(typeSpec, bases, SbkObjectType_TypeF());
 
-    for (int i = 0; i < PySequence_Fast_GET_SIZE(bases); ++i) {
-        auto *st = reinterpret_cast<PyTypeObject *>(PySequence_Fast_GET_ITEM(bases, i));
-        BindingManager::instance().addClassInheritance(st, type);
-    }
-
     auto sotp = PepType_SOTP(type);
     if (wrapperFlags & DeleteInMainThread)
         sotp->delete_in_main_thread = 1;
+    sotp->type_behaviour = (wrapperFlags & Value) != 0
+                           ? BEHAVIOUR_VALUETYPE : BEHAVIOUR_OBJECTTYPE;
 
     setOriginalName(type, originalName);
     setDestructorFunction(type, cppObjDtor);
@@ -1006,16 +1027,19 @@ introduceWrapperType(PyObject *enclosingObject,
 
 void setSubTypeInitHook(PyTypeObject *type, SubTypeInitHook func)
 {
+    assert(SbkObjectType_Check(type));
     PepType_SOTP(type)->subtype_init = func;
 }
 
 void *getTypeUserData(PyTypeObject *type)
 {
+    assert(SbkObjectType_Check(type));
     return PepType_SOTP(type)->user_data;
 }
 
 void setTypeUserData(PyTypeObject *type, void *userData, DeleteUserDataFunc d_func)
 {
+    assert(SbkObjectType_Check(type));
     auto *sotp = PepType_SOTP(type);
     sotp->user_data = userData;
     sotp->d_func = d_func;
@@ -1417,10 +1441,15 @@ PyObject *newObject(PyTypeObject *instanceType,
 {
     // Try to find the exact type of cptr.
     if (!isExactType) {
-        if (PyTypeObject *exactType = ObjectType::typeForTypeName(typeName))
+        if (PyTypeObject *exactType = ObjectType::typeForTypeName(typeName)) {
             instanceType = exactType;
-        else
-            instanceType = BindingManager::instance().resolveType(&cptr, instanceType);
+        } else {
+            auto resolved = BindingManager::instance().findDerivedType(cptr, instanceType);
+            if (resolved.first != nullptr) {
+                instanceType = resolved.first;
+                cptr = resolved.second;
+            }
+        }
     }
 
     bool shouldCreate = true;
@@ -1631,7 +1660,7 @@ void deallocData(SbkObject *self, bool cleanup)
     }
     delete self->d; // PYSIDE-205: always delete d.
     Py_XDECREF(self->ob_dict);
-    Py_TYPE(self)->tp_free(self);
+    PepExt_TypeCallFree(reinterpret_cast<PyObject *>(self));
 }
 
 void setTypeUserData(SbkObject *wrapper, void *userData, DeleteUserDataFunc d_func)
@@ -1723,6 +1752,11 @@ static std::vector<PyTypeObject *> getBases(SbkObject *self)
         : std::vector<PyTypeObject *>(1, Py_TYPE(self));
 }
 
+static bool isValueType(SbkObject *self)
+{
+    return PepType_SOTP(Py_TYPE(self))->type_behaviour == BEHAVIOUR_VALUETYPE;
+}
+
 void _debugFormat(std::ostream &s, SbkObject *self)
 {
     assert(self);
@@ -1746,6 +1780,8 @@ void _debugFormat(std::ostream &s, SbkObject *self)
         s << " [validCppObject]";
     if (d->cppObjectCreated)
         s << " [wasCreatedByPython]";
+    s << (isValueType(self) ? " [value]" : " [object]");
+
     if (d->parentInfo) {
         if (auto *parent = d->parentInfo->parent)
             s << ", parent=" << reinterpret_cast<PyObject *>(parent)->ob_type->tp_name
@@ -1776,8 +1812,9 @@ std::string info(SbkObject *self)
     s << "hasOwnership...... " << bool(self->d->hasOwnership) << "\n"
          "containsCppWrapper " << self->d->containsCppWrapper << "\n"
          "validCppObject.... " << self->d->validCppObject << "\n"
-         "wasCreatedByPython " << self->d->cppObjectCreated << "\n";
-
+         "wasCreatedByPython " << self->d->cppObjectCreated << "\n"
+         "value......        " << isValueType(self) << "\n"
+         "reference count... " << reinterpret_cast<PyObject *>(self)->ob_refcnt << '\n';
 
     if (self->d->parentInfo && self->d->parentInfo->parent) {
         s << "parent............ ";
index 90ec8cb4e0fa3bb7820408808d9aeff542e989aa..4835c481098a65f0952397761e4decd120ed868e 100644 (file)
@@ -59,7 +59,9 @@ using SubTypeInitHook = void (*)(PyTypeObject *, PyObject *, PyObject *);
 /// PYSIDE-1019: Set the function to select the current feature.
 /// Return value is the previous content.
 using SelectableFeatureHook = void (*)(PyTypeObject *);
+using SelectableFeatureCallback = void (*)(bool);
 LIBSHIBOKEN_API SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func);
+LIBSHIBOKEN_API void setSelectableFeatureCallback(SelectableFeatureCallback func);
 
 /// PYSIDE-1626: Enforcing a context switch without further action.
 LIBSHIBOKEN_API void SbkObjectType_UpdateFeature(PyTypeObject *type);
@@ -198,14 +200,15 @@ LIBSHIBOKEN_API const char *getOriginalName(PyTypeObject *self);
 LIBSHIBOKEN_API void setTypeDiscoveryFunctionV2(PyTypeObject *self, TypeDiscoveryFuncV2 func);
 LIBSHIBOKEN_API void copyMultipleInheritance(PyTypeObject *self, PyTypeObject *other);
 LIBSHIBOKEN_API void setMultipleInheritanceFunction(PyTypeObject *self, MultipleInheritanceInitFunction func);
-LIBSHIBOKEN_API MultipleInheritanceInitFunction getMultipleInheritanceFunction(PyTypeObject *self);
+LIBSHIBOKEN_API MultipleInheritanceInitFunction getMultipleInheritanceFunction(PyTypeObject *type);
 
 LIBSHIBOKEN_API void setDestructorFunction(PyTypeObject *self, ObjectDestructor func);
 
 enum WrapperFlags
 {
     InnerClass = 0x1,
-    DeleteInMainThread = 0x2
+    DeleteInMainThread = 0x2,
+    Value = 0x4
 };
 
 /**
@@ -226,13 +229,12 @@ enum WrapperFlags
  *  \returns                true if the initialization went fine, false otherwise.
  */
 LIBSHIBOKEN_API PyTypeObject *introduceWrapperType(PyObject *enclosingObject,
-                                                    const char *typeName,
-                                                    const char *originalName,
-                                                    PyType_Spec *typeSpec,
-                                                    ObjectDestructor cppObjDtor,
-                                                    PyTypeObject *baseType,
-                                                    PyObject *baseTypes,
-                                                    unsigned wrapperFlags = 0);
+                                                   const char *typeName,
+                                                   const char *originalName,
+                                                   PyType_Spec *typeSpec,
+                                                   ObjectDestructor cppObjDtor,
+                                                   PyObject *bases,
+                                                   unsigned wrapperFlags = 0);
 
 /**
  *  Set the subtype init hook for a type.
index a9b87f7f48f5b7853175f3b8b539d1f6a10b6db6..83c927ae5c611800438a174fb440d3c700635a22 100644 (file)
@@ -7,6 +7,7 @@
 #include "bindingmanager.h"
 #include "gilstate.h"
 #include "helper.h"
+#include "sbkmodule.h"
 #include "sbkstring.h"
 #include "sbkstaticstrings.h"
 #include "sbkfeature_base.h"
 #include <cstddef>
 #include <cstring>
 #include <fstream>
+#include <iostream>
 #include <mutex>
+#include <string_view>
 #include <unordered_map>
+#include <unordered_set>
+
+// GraphNode for the dependency graph. It keeps a pointer to
+// the TypeInitStruct to be able to lazily create the type and hashes
+// by the full type name.
+struct GraphNode
+{
+    explicit GraphNode(Shiboken::Module::TypeInitStruct *i) : name(i->fullName), initStruct(i) {}
+    explicit GraphNode(const char *n) : name(n), initStruct(nullptr) {} // Only for searching
+
+    std::string_view name;
+    Shiboken::Module::TypeInitStruct *initStruct;
+
+    friend bool operator==(const GraphNode &n1, const GraphNode &n2) { return n1.name == n2.name; }
+    friend bool operator!=(const GraphNode &n1, const GraphNode &n2) { return n1.name != n2.name; }
+};
+
+template <>
+struct std::hash<GraphNode> {
+    size_t operator()(const GraphNode &n) const noexcept
+    {
+        return std::hash<std::string_view>{}(n.name);
+    }
+};
 
 namespace Shiboken
 {
 
 using WrapperMap = std::unordered_map<const void *, SbkObject *>;
 
-class Graph
+template <class NodeType>
+class BaseGraph
 {
 public:
-    using NodeList = std::vector<PyTypeObject *>;
-    using Edges = std::unordered_map<PyTypeObject *, NodeList>;
+    using NodeList = std::vector<NodeType>;
+    using NodeSet = std::unordered_set<NodeType>;
+
+    using Edges = std::unordered_map<NodeType, NodeList>;
 
     Edges m_edges;
 
-    Graph() = default;
+    BaseGraph() = default;
 
-    void addEdge(PyTypeObject *from, PyTypeObject *to)
+    void addEdge(NodeType from, NodeType to)
     {
         m_edges[from].push_back(to);
     }
 
-#ifndef NDEBUG
-    void dumpDotGraph() const
+    NodeSet nodeSet() const
     {
-        std::ofstream file("/tmp/shiboken_graph.dot");
-
-        file << "digraph D {\n";
-
+        NodeSet result;
         for (const auto &p : m_edges) {
-            auto *node1 = p.first;
-            const NodeList &nodeList = p.second;
-            for (const PyTypeObject *o : nodeList) {
-                auto *node2 = o;
-                file << '"' << node2->tp_name << "\" -> \""
-                    << node1->tp_name << "\"\n";
-            }
+            result.insert(p.first);
+            for (const auto node2 : p.second)
+                result.insert(node2);
         }
-        file << "}\n";
+        return result;
     }
-#endif
+};
+
+class Graph : public BaseGraph<GraphNode>
+{
+public:
+    using TypeCptrPair = BindingManager::TypeCptrPair;
 
-    PyTypeObject *identifyType(void **cptr, PyTypeObject *type, PyTypeObject *baseType) const
+    TypeCptrPair identifyType(void *cptr, PyTypeObject *type, PyTypeObject *baseType) const
     {
-        auto edgesIt = m_edges.find(type);
-        if (edgesIt != m_edges.end()) {
-            const NodeList &adjNodes = m_edges.find(type)->second;
-            for (PyTypeObject *node : adjNodes) {
-                PyTypeObject *newType = identifyType(cptr, node, baseType);
-                if (newType)
-                    return newType;
-            }
-        }
-        void *typeFound = nullptr;
-        auto *sotp = PepType_SOTP(type);
-        if (sotp->type_discovery)
-            typeFound = sotp->type_discovery(*cptr, baseType);
-        if (typeFound) {
-            // This "typeFound != type" is needed for backwards compatibility with old modules using a newer version of
-            // libshiboken because old versions of type_discovery function used to return a PyTypeObject *instead of
-            // a possible variation of the C++ instance pointer (*cptr).
-            if (typeFound != type)
-                *cptr = typeFound;
-            return type;
-        }
-        return nullptr;
+        return identifyType(cptr, GraphNode(type->tp_name), type, baseType);
     }
-};
 
+    bool dumpTypeGraph(const char *fileName) const;
 
-#ifndef NDEBUG
-static void showWrapperMap(const WrapperMap &wrapperMap)
+private:
+    TypeCptrPair identifyType(void *cptr, const GraphNode &typeNode, PyTypeObject *type,
+                              PyTypeObject *baseType) const;
+};
+
+Graph::TypeCptrPair Graph::identifyType(void *cptr,
+                                        const GraphNode &typeNode, PyTypeObject *type,
+                                        PyTypeObject *baseType) const
 {
-    if (Shiboken::pyVerbose() > 0) {
-        fprintf(stderr, "-------------------------------\n");
-        fprintf(stderr, "WrapperMap: %p (size: %d)\n", &wrapperMap, (int) wrapperMap.size());
-        for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) {
-            const SbkObject *sbkObj = it->second;
-            fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", it->first,
-                    static_cast<const void *>(sbkObj),
-                    (Py_TYPE(sbkObj))->tp_name,
-                    int(Py_REFCNT(reinterpret_cast<const PyObject *>(sbkObj))));
+    assert(typeNode.initStruct != nullptr || type != nullptr);
+    auto edgesIt = m_edges.find(typeNode);
+    if (edgesIt != m_edges.end()) {
+        const NodeList &adjNodes = edgesIt->second;
+        for (const auto &node : adjNodes) {
+            auto newType = identifyType(cptr, node, nullptr, baseType);
+            if (newType.first != nullptr)
+                return newType;
         }
-        fprintf(stderr, "-------------------------------\n");
     }
+
+    if (type == nullptr) {
+        if (typeNode.initStruct->type == nullptr) // Layzily create type
+            type = Shiboken::Module::get(*typeNode.initStruct);
+        else
+            type = typeNode.initStruct->type;
+    }
+
+    auto *sotp = PepType_SOTP(type);
+    if (sotp->type_discovery != nullptr) {
+        if (void *derivedCPtr = sotp->type_discovery(cptr, baseType))
+            return {type, derivedCPtr};
+    }
+    return {nullptr, nullptr};
+}
+
+static void formatDotNode(std::string_view name, std::ostream &file)
+{
+    auto lastDot = name.rfind('.');
+    file << "    \"" << name << "\" [ label=";
+    if (lastDot != std::string::npos) {
+        file << '"' << name.substr(lastDot + 1) << "\" tooltip=\""
+             << name.substr(0, lastDot) << '"';
+    } else {
+        file << '"' << name << '"';
+    }
+    file << " ]\n";
+}
+
+bool Graph::dumpTypeGraph(const char *fileName) const
+{
+    std::ofstream file(fileName);
+    if (!file.good())
+        return false;
+
+    file << "digraph D {\n";
+
+    // Define nodes with short names
+    for (const auto &node : nodeSet())
+        formatDotNode(node.name, file);
+
+    // Write edges
+    for (const auto &p : m_edges) {
+        const auto &node1 = p.first;
+        const NodeList &nodeList = p.second;
+        for (const auto &node2 : nodeList)
+            file << "    \"" << node2.name << "\" -> \"" << node1.name << "\"\n";
+    }
+    file << "}\n";
+    return true;
 }
-#endif
 
 struct BindingManager::BindingManagerPrivate {
     using DestructorEntries = std::vector<DestructorEntry>;
@@ -115,9 +174,6 @@ struct BindingManager::BindingManagerPrivate {
     std::recursive_mutex wrapperMapLock;
     Graph classHierarchy;
     DestructorEntries deleteInMainThread;
-    bool destroying;
-
-    BindingManagerPrivate() : destroying(false) {}
 
     bool releaseWrapper(void *cptr, SbkObject *wrapper, const int *bases = nullptr);
     bool releaseWrapperHelper(void *cptr, SbkObject *wrapper);
@@ -189,7 +245,8 @@ BindingManager::~BindingManager()
     debugRemoveFreeHook();
 #endif
 #ifndef NDEBUG
-    showWrapperMap(m_d->wrapperMapper);
+    if (Shiboken::pyVerbose() > 0)
+        dumpWrapperMap();
 #endif
     /* Cleanup hanging references. We just invalidate them as when
      * the BindingManager is being destroyed the interpreter is alredy
@@ -363,15 +420,24 @@ PyObject *BindingManager::getOverride(const void *cptr,
     return nullptr;
 }
 
-void BindingManager::addClassInheritance(PyTypeObject *parent, PyTypeObject *child)
+void BindingManager::addClassInheritance(Module::TypeInitStruct *parent,
+                                         Module::TypeInitStruct *child)
 {
-    m_d->classHierarchy.addEdge(parent, child);
+    m_d->classHierarchy.addEdge(GraphNode(parent), GraphNode(child));
 }
 
+BindingManager::TypeCptrPair BindingManager::findDerivedType(void *cptr, PyTypeObject *type) const
+{
+    return m_d->classHierarchy.identifyType(cptr, type, type);
+}
+
+// FIXME PYSIDE7: remove, just for compatibility
 PyTypeObject *BindingManager::resolveType(void **cptr, PyTypeObject *type)
 {
-    PyTypeObject *identifiedType = m_d->classHierarchy.identifyType(cptr, type, type);
-    return identifiedType ? identifiedType : type;
+    auto result = findDerivedType(*cptr, type);
+    if (result.second != nullptr)
+        *cptr = result.second;
+    return result.first != nullptr ? result.first : type;
 }
 
 std::set<PyObject *> BindingManager::getAllPyObjects()
@@ -395,6 +461,27 @@ void BindingManager::visitAllPyObjects(ObjectVisitor visitor, void *data)
     }
 }
 
+bool BindingManager::dumpTypeGraph(const char *fileName) const
+{
+    return m_d->classHierarchy.dumpTypeGraph(fileName);
+}
+
+void BindingManager::dumpWrapperMap()
+{
+    const auto &wrapperMap = m_d->wrapperMapper;
+    std::cerr <<  "-------------------------------\n"
+        << "WrapperMap size: " << wrapperMap.size() << " Types: "
+        << m_d->classHierarchy.nodeSet().size() << '\n';
+    for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) {
+        const SbkObject *sbkObj = it->second;
+        std::cerr << "key: " << it->first << ", value: "
+            << static_cast<const void *>(sbkObj) << " ("
+            << (Py_TYPE(sbkObj))->tp_name << ", refcnt: "
+            << Py_REFCNT(reinterpret_cast<const PyObject *>(sbkObj)) << ")\n";
+    }
+    std::cerr << "-------------------------------\n";
+}
+
 static bool isPythonType(PyTypeObject *type)
 {
     // This is a type which should be called by multiple inheritance.
@@ -408,6 +495,8 @@ bool callInheritedInit(PyObject *self, PyObject *args, PyObject *kwds,
     using Shiboken::AutoDecRef;
 
     static PyObject *const _init = String::createStaticString("__init__");
+    static PyObject *objectInit =
+        PyObject_GetAttr(reinterpret_cast<PyObject *>(&PyBaseObject_Type), _init);
 
     // A native C++ self cannot have multiple inheritance.
     if (!Object::isUserType(self))
@@ -441,6 +530,10 @@ bool callInheritedInit(PyObject *self, PyObject *args, PyObject *kwds,
     if (subType == &PyBaseObject_Type)
         return false;
     AutoDecRef func(PyObject_GetAttr(obSubType, _init));
+    // PYSIDE-2654: If this has no implementation then we get object.__init__
+    //              but that is the same case like above.
+    if (func == objectInit)
+        return false;
     // PYSIDE-2294: We need to explicitly ignore positional args in a mixin class.
     SBK_UNUSED(args);
     AutoDecRef newArgs(PyTuple_New(1));
index 4b21ae83533f89b5b3378319adab548f46995de5..54c4e486a33aced79ad4b9a4a953fe71be85d792 100644 (file)
@@ -5,14 +5,20 @@
 #define BINDINGMANAGER_H
 
 #include "sbkpython.h"
-#include <set>
 #include "shibokenmacros.h"
 
+#include <set>
+#include <utility>
+
 struct SbkObject;
 
 namespace Shiboken
 {
 
+namespace Module {
+struct TypeInitStruct;
+}
+
 struct DestructorEntry;
 
 using ObjectVisitor = void (*)(SbkObject *, void *);
@@ -38,7 +44,15 @@ public:
     SbkObject *retrieveWrapper(const void *cptr);
     PyObject *getOverride(const void *cptr, PyObject *nameCache[], const char *methodName);
 
-    void addClassInheritance(PyTypeObject *parent, PyTypeObject *child);
+    void addClassInheritance(Module::TypeInitStruct *parent, Module::TypeInitStruct *child);
+    /// Try to find the correct type of cptr via type discovery knowing that it's at least
+    /// of type \p type. If a derived class is found, it returns a cptr cast to the type
+    /// (which may be different in case of  multiple inheritance.
+    /// \param cptr a pointer to the instance of type \p type
+    /// \param type type of cptr
+    using TypeCptrPair = std::pair<PyTypeObject *, void *>;
+    TypeCptrPair findDerivedType(void *cptr, PyTypeObject *type) const;
+
     /**
      * Try to find the correct type of *cptr knowing that it's at least of type \p type.
      * In case of multiple inheritance this function may change the contents of cptr.
@@ -46,7 +60,7 @@ public:
      * \param type type of *cptr
      * \warning This function is slow, use it only as last resort.
      */
-    PyTypeObject *resolveType(void **cptr, PyTypeObject *type);
+    [[deprecated]] PyTypeObject *resolveType(void **cptr, PyTypeObject *type);
 
     std::set<PyObject *> getAllPyObjects();
 
@@ -59,6 +73,9 @@ public:
      */
     void visitAllPyObjects(ObjectVisitor visitor, void *data);
 
+    bool dumpTypeGraph(const char *fileName) const;
+    void dumpWrapperMap();
+
 private:
     ~BindingManager();
     BindingManager();
index 9c75c00db03d48f56d99d1731ae08754e2a965b0..46af68956e4d0451208126da722004c195881de0 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <iomanip>
 #include <iostream>
+#include <climits>
 #include <cstring>
 #include <cstdarg>
 #include <cctype>
@@ -43,14 +44,21 @@ static std::optional<int> getIntAttr(PyObject *obj, const char *what)
     return std::nullopt;
 }
 
+static bool verbose = false;
+
 static void formatTypeTuple(PyObject *t, const char *what, std::ostream &str);
 
 static void formatPyTypeObject(const PyTypeObject *obj, std::ostream &str, bool verbose)
 {
-    if (obj) {
+    if (obj == nullptr) {
+        str << '0';
+        return;
+    }
+
+    str << '"' << obj->tp_name << '"';
+    if (verbose) {
         bool immutableType = false;
-        str << '"' << obj->tp_name << "\", 0x" << std::hex
-            << obj->tp_flags << std::dec;
+        str << ", 0x" << std::hex << obj->tp_flags << std::dec;
         if (obj->tp_flags & Py_TPFLAGS_HEAPTYPE)
             str << " [heaptype]";
         if (obj->tp_flags & Py_TPFLAGS_BASETYPE)
@@ -79,7 +87,6 @@ static void formatPyTypeObject(const PyTypeObject *obj, std::ostream &str, bool
             str << " [readying]";
         if (obj->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR)
             str << " [method_descriptor]";
-#if PY_VERSION_HEX >= 0x03090000
 #  ifndef Py_LIMITED_API
         if (obj->tp_flags & Py_TPFLAGS_HAVE_VECTORCALL)
             str << " [vectorcall]";
@@ -97,7 +104,6 @@ static void formatPyTypeObject(const PyTypeObject *obj, std::ostream &str, bool
             str << " [sequence]";
 #       endif // !Py_LIMITED_API
 #  endif // 3.10
-#endif // 3.9
         if (obj->tp_basicsize != 0)
             str << ", basicsize=" << obj->tp_basicsize;
         if (verbose) {
@@ -110,8 +116,6 @@ static void formatPyTypeObject(const PyTypeObject *obj, std::ostream &str, bool
                 }
             }
         }
-    } else {
-        str << '0';
     }
 }
 
@@ -208,6 +212,8 @@ static void formatPyUnicode(PyObject *obj, std::ostream &str)
 {
     // Note: The below call create the PyCompactUnicodeObject.utf8 representation
     str << '"' << _PepUnicode_AsString(obj) << '"';
+    if (!verbose)
+        return;
 
     str << " (" << PyUnicode_GetLength(obj) << ')';
     const auto kind = _PepUnicode_KIND(obj);
@@ -324,7 +330,11 @@ static void formatPyObjectHelper(PyObject *obj, std::ostream &str)
         str << "False";
         return;
     }
-    str << "refs=" << Py_REFCNT(obj) << ", ";
+    const auto refs = Py_REFCNT(obj);
+    if (refs == UINT_MAX) // _Py_IMMORTAL_REFCNT
+        str << "immortal, ";
+    else
+        str << "refs=" << refs << ", ";
     if (PyType_Check(obj)) {
         str << "type: ";
         formatPyTypeObject(reinterpret_cast<PyTypeObject *>(obj), str, true);
@@ -332,8 +342,15 @@ static void formatPyObjectHelper(PyObject *obj, std::ostream &str)
     }
     formatPyTypeObject(obj->ob_type, str, false);
     str << ", ";
-    if (PyLong_Check(obj))
-        str << PyLong_AsLong(obj);
+    if (PyLong_Check(obj)) {
+        const auto llv = PyLong_AsLongLong(obj);
+        if (PyErr_Occurred() != PyExc_OverflowError) {
+            str << llv;
+        } else {
+            PyErr_Clear();
+            str << "0x" << std::hex << PyLong_AsUnsignedLongLong(obj) << std::dec;
+        }
+    }
     else if (PyFloat_Check(obj))
         str << PyFloat_AsDouble(obj);
     else if (PyUnicode_Check(obj))
@@ -419,6 +436,18 @@ std::ostream &operator<<(std::ostream &str, const debugPyBuffer &b)
     return str;
 }
 
+std::ios_base &debugVerbose(std::ios_base &s)
+{
+    verbose = true;
+    return s;
+}
+
+std::ios_base &debugBrief(std::ios_base &s)
+{
+    verbose = false;
+    return s;
+}
+
 #ifdef _WIN32
 // Converts a Unicode string to a string encoded in the Windows console's
 // code page via wchar_t for use with argv (PYSIDE-1425).
index 4e14b8c4bd45933eca1143effae1c254db2f4df3..f226e8c2499c371878fb2bfc037e4e8af72ae056 100644 (file)
@@ -112,7 +112,8 @@ LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugSbkObject
 LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyTypeObject &o);
 LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyBuffer &b);
 LIBSHIBOKEN_API std::ostream &operator<<(std::ostream &str, const debugPyArrayObject &b);
-
+LIBSHIBOKEN_API std::ios_base &debugVerbose(std::ios_base &s);
+LIBSHIBOKEN_API std::ios_base &debugBrief(std::ios_base &s);
 } // namespace Shiboken
 
 
diff --git a/sources/shiboken6/libshiboken/pep384ext.h b/sources/shiboken6/libshiboken/pep384ext.h
new file mode 100644 (file)
index 0000000..021c53d
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PEP384EXT_H
+#define PEP384EXT_H
+
+#include "pep384impl.h"
+
+/// Returns the allocator slot of the PyTypeObject.
+inline allocfunc PepExt_Type_GetAllocSlot(PyTypeObject *t)
+{
+    return reinterpret_cast<allocfunc>(PepType_GetSlot(t, Py_tp_alloc));
+}
+
+/// Invokes the allocator slot of the PyTypeObject.
+template <class Type>
+inline Type *PepExt_TypeCallAlloc(PyTypeObject *t, Py_ssize_t nitems)
+{
+    PyObject *result = PepExt_Type_GetAllocSlot(t)(t, nitems);
+    return reinterpret_cast<Type *>(result);
+}
+
+/// Returns the getattro slot of the PyTypeObject.
+inline getattrofunc PepExt_Type_GetGetAttroSlot(PyTypeObject *t)
+{
+    return reinterpret_cast<getattrofunc>(PepType_GetSlot(t, Py_tp_getattro));
+}
+
+/// Returns the setattro slot of the PyTypeObject.
+inline setattrofunc PepExt_Type_GetSetAttroSlot(PyTypeObject *t)
+{
+    return reinterpret_cast<setattrofunc>(PepType_GetSlot(t, Py_tp_setattro));
+}
+
+/// Returns the descr_get slot of the PyTypeObject.
+inline descrgetfunc PepExt_Type_GetDescrGetSlot(PyTypeObject *t)
+{
+    return reinterpret_cast<descrgetfunc>(PepType_GetSlot(t, Py_tp_descr_get));
+}
+
+/// Invokes the descr_get slot of the PyTypeObject.
+inline PyObject *PepExt_Type_CallDescrGet(PyObject *self, PyObject *obj, PyObject *type)
+{
+    return PepExt_Type_GetDescrGetSlot(Py_TYPE(self))(self, obj, type);
+}
+
+/// Returns the descr_set slot of the PyTypeObject.
+inline descrsetfunc PepExt_Type_GetDescrSetSlot(PyTypeObject *t)
+{
+    return reinterpret_cast<descrsetfunc>(PepType_GetSlot(t, Py_tp_descr_set));
+}
+
+/// Returns the call slot of the PyTypeObject.
+inline ternaryfunc PepExt_Type_GetCallSlot(PyTypeObject *t)
+{
+    return reinterpret_cast<ternaryfunc>(PepType_GetSlot(t, Py_tp_call));
+}
+
+/// Returns the new slot of the PyTypeObject.
+inline newfunc PepExt_Type_GetNewSlot(PyTypeObject *t)
+{
+    return reinterpret_cast<newfunc>(PepType_GetSlot(t, Py_tp_new));
+}
+
+/// Returns the init slot of the PyTypeObject.
+inline initproc PepExt_Type_GetInitSlot(PyTypeObject *t)
+{
+    return reinterpret_cast<initproc>(PepType_GetSlot(t, Py_tp_init));
+}
+
+/// Returns the free slot of the PyTypeObject.
+inline freefunc PepExt_Type_GetFreeSlot(PyTypeObject *t)
+{
+    return reinterpret_cast<freefunc>(PepType_GetSlot(t, Py_tp_free));
+}
+
+/// Invokes the free slot of the PyTypeObject.
+inline void PepExt_TypeCallFree(PyTypeObject *t, void *object)
+{
+    PepExt_Type_GetFreeSlot(t)(object);
+}
+
+/// Invokes the free slot of the PyTypeObject.
+inline void PepExt_TypeCallFree(PyObject *object)
+{
+    PepExt_Type_GetFreeSlot(Py_TYPE(object))(object);
+}
+
+#endif // PEP384EXT_H
index 37e51921e6888ca0f9c9798d5a58d56b4df334bc..2b04af8572879eab630325e0d0e3179175a438b5 100644 (file)
@@ -105,13 +105,13 @@ static PyType_Spec typeprobe_spec = {
 static void
 check_PyTypeObject_valid()
 {
-    auto *obtype = reinterpret_cast<PyObject *>(&PyType_Type);
-    auto *probe_tp_base = reinterpret_cast<PyTypeObject *>(
-        PyObject_GetAttr(obtype, Shiboken::PyMagicName::base()));
+    auto *typetype = &PyType_Type;
+    auto *obtype = reinterpret_cast<PyObject *>(typetype);
+    auto *probe_tp_base_obj = PyObject_GetAttr(obtype, Shiboken::PyMagicName::base());
+    auto *probe_tp_base = reinterpret_cast<PyTypeObject *>(probe_tp_base_obj);
     auto *probe_tp_bases = PyObject_GetAttr(obtype, Shiboken::PyMagicName::bases());
-    auto *check = reinterpret_cast<PyTypeObject *>(
-        PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases));
-    auto *typetype = reinterpret_cast<PyTypeObject *>(obtype);
+    auto *checkObj = PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases);
+    auto *check = reinterpret_cast<PyTypeObject *>(checkObj);
     PyObject *w = PyObject_GetAttr(obtype, Shiboken::PyMagicName::weakrefoffset());
     long probe_tp_weakrefoffset = PyLong_AsLong(w);
     PyObject *d = PyObject_GetAttr(obtype, Shiboken::PyMagicName::dictoffset());
@@ -149,8 +149,8 @@ check_PyTypeObject_valid()
         || probe_tp_mro             != typetype->tp_mro
         || Py_TPFLAGS_DEFAULT       != (check->tp_flags & Py_TPFLAGS_DEFAULT))
         Py_FatalError("The structure of type objects has changed!");
-    Py_DECREF(check);
-    Py_DECREF(probe_tp_base);
+    Py_DECREF(checkObj);
+    Py_DECREF(probe_tp_base_obj);
     Py_DECREF(w);
     Py_DECREF(d);
     Py_DECREF(probe_tp_bases);
@@ -482,6 +482,22 @@ Pep_GetVerboseFlag()
 }
 #endif // Py_LIMITED_API
 
+// Support for pyerrors.h
+
+#if defined(Py_LIMITED_API) || PY_VERSION_HEX < 0x030C0000
+// Emulate PyErr_GetRaisedException() using the deprecated PyErr_Fetch()/PyErr_Store()
+PyObject *PepErr_GetRaisedException()
+{
+    PyObject *type{};
+    PyObject *value{};
+    PyObject *traceback{};
+    PyErr_Fetch(&type, &value, &traceback);
+    Py_XINCREF(value);
+    PyErr_Restore(type, value, traceback);
+    return value;
+}
+#endif // Limited or < 3.12
+
 /*****************************************************************************
  *
  * Support for code.h
@@ -722,11 +738,8 @@ PyTypeObject *PepStaticMethod_TypePtr = nullptr;
 static PyTypeObject *
 getStaticMethodType(void)
 {
-    // this works for Python 3, only
-    //    "StaticMethodType = type(str.__dict__['maketrans'])\n";
     static const char prog[] =
-        "from xxsubtype import spamlist\n"
-        "result = type(spamlist.__dict__['staticmeth'])\n";
+        "result = type(str.__dict__['maketrans'])\n";
     return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
 }
 
@@ -994,33 +1007,108 @@ long _PepRuntimeVersion()
  *
  */
 
+///////////////////////////////////////////////////////////////////////
+//
+// PEP 697: Support for embedded type structures.
+//
+// According to `https://docs.python.org/3/c-api/object.html?highlight=pyobject_gettypedata#c.PyObject_GetTypeData`
+// the function `PyObject_GetTypeData` should belong to the Stable API
+// since version 3.12.0, but it does not. We use instead some copies
+// from Python source code.
+
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+
+# define PepObject_GetTypeData PyObject_GetTypeData
+
+SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *type)
+{
+    // PYSIDE-2676: Use the meta type explicitly.
+    //              A derived type would fail the offset calculation.
+    static auto *meta = SbkObjectType_TypeF();
+    assert(SbkObjectType_Check(type));
+    auto *obType = reinterpret_cast<PyObject *>(type);
+    void *data = PyObject_GetTypeData(obType, meta);
+    return reinterpret_cast<SbkObjectTypePrivate *>(data);
+}
+
+void PepType_SOTP_delete(PyTypeObject * /*type*/)
+{
+}
+
+#else
+
+// The following comments are directly copied from Python 3.12
+//
+
+// Make sure we have maximum alignment, even if the current compiler
+// does not support max_align_t. Note that:
+// - Autoconf reports alignment of unknown types to 0.
+// - 'long double' has maximum alignment on *most* platforms,
+//   looks like the best we can do for pre-C11 compilers.
+// - The value is tested, see test_alignof_max_align_t
+#  if !defined(ALIGNOF_MAX_ALIGN_T) || ALIGNOF_MAX_ALIGN_T == 0
+#    undef ALIGNOF_MAX_ALIGN_T
+#    define ALIGNOF_MAX_ALIGN_T alignof(long double)
+#  endif
+
+/* Align up to the nearest multiple of alignof(max_align_t)
+ * (like _Py_ALIGN_UP, but for a size rather than pointer)
+ */
+static Py_ssize_t _align_up(Py_ssize_t size)
+{
+    return (size + ALIGNOF_MAX_ALIGN_T - 1) & ~(ALIGNOF_MAX_ALIGN_T - 1);
+}
+
+static void *PepObject_GetTypeData(PyObject *obj, PyTypeObject *cls)
+{
+    assert(PyObject_TypeCheck(obj, cls));
+    return reinterpret_cast<char *>(obj) + _align_up(cls->tp_base->tp_basicsize);
+}
+//
+///////////////////////////////////////////////////////////////////////
+
 /*
  * PyTypeObject extender
  */
+
 static std::unordered_map<PyTypeObject *, SbkObjectTypePrivate > SOTP_extender{};
 static thread_local PyTypeObject *SOTP_key{};
 static thread_local SbkObjectTypePrivate *SOTP_value{};
 
-SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *sbkType)
+SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *type)
 {
-    if (sbkType == SOTP_key)
+    static auto *meta = SbkObjectType_TypeF();
+    static bool use_312 = _PepRuntimeVersion() >= 0x030C00;
+    assert(SbkObjectType_Check(type));
+    if (use_312) {
+        auto *obType = reinterpret_cast<PyObject *>(type);
+        void *data = PepObject_GetTypeData(obType, meta);
+        return reinterpret_cast<SbkObjectTypePrivate *>(data);
+    }
+    if (type == SOTP_key)
         return SOTP_value;
-    auto it = SOTP_extender.find(sbkType);
+    auto it = SOTP_extender.find(type);
     if (it == SOTP_extender.end()) {
-        it = SOTP_extender.insert({sbkType, {}}).first;
+        it = SOTP_extender.insert({type, {}}).first;
         memset(&it->second, 0, sizeof(SbkObjectTypePrivate));
     }
-    SOTP_key = sbkType;
+    SOTP_key = type;
     SOTP_value = &it->second;
     return SOTP_value;
 }
 
-void PepType_SOTP_delete(PyTypeObject *sbkType)
+void PepType_SOTP_delete(PyTypeObject *type)
 {
-    SOTP_extender.erase(sbkType);
+    static bool use_312 = _PepRuntimeVersion() >= 0x030C00;
+    assert(SbkObjectType_Check(type));
+    if (use_312)
+        return;
+    SOTP_extender.erase(type);
     SOTP_key = nullptr;
 }
 
+#endif // !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+
 /*
  * SbkEnumType extender
  */
@@ -1030,6 +1118,7 @@ static thread_local SbkEnumTypePrivate *SETP_value{};
 
 SbkEnumTypePrivate *PepType_SETP(SbkEnumType *enumType)
 {
+    // PYSIDE-2230: This makes no sense at all for Enum types.
     if (enumType == SETP_key)
         return SETP_value;
     auto it = SETP_extender.find(enumType);
@@ -1087,6 +1176,39 @@ int PepType_SetDict(PyTypeObject *type, PyObject *dict)
     return 0;
 }
 
+// Pre 3.10, PyType_GetSlot() would only work for heap types.
+// FIXME: PyType_GetSlot() can be used unconditionally when the
+// minimum limited API version is >= 3.10.
+void *PepType_GetSlot(PyTypeObject *type, int aSlot)
+{
+    static const bool is310 = _PepRuntimeVersion() >= 0x030A00;
+    if (is310 || (type->tp_flags & Py_TPFLAGS_HEAPTYPE) != 0)
+        return PyType_GetSlot(type, aSlot);
+
+    switch (aSlot) {
+    case Py_tp_alloc:
+        return reinterpret_cast<void *>(type->tp_alloc);
+    case Py_tp_getattro:
+        return reinterpret_cast<void *>(type->tp_getattro);
+    case Py_tp_setattro:
+        return reinterpret_cast<void *>(type->tp_setattro);
+    case Py_tp_descr_get:
+        return reinterpret_cast<void *>(type->tp_descr_get);
+    case Py_tp_descr_set:
+        return reinterpret_cast<void *>(type->tp_descr_set);
+    case Py_tp_call:
+        return reinterpret_cast<void *>(type->tp_call);
+    case Py_tp_new:
+        return reinterpret_cast<void *>(type->tp_new);
+    case Py_tp_init:
+        return reinterpret_cast<void *>(type->tp_init);
+    case Py_tp_free:
+        return reinterpret_cast<void *>(type->tp_free);
+    }
+    assert(false);
+    return nullptr;
+}
+
 /***************************************************************************
  *
  * PYSIDE-535: The enum/flag error
index 39a6f3d13a9f6804ec3fb0791cbd243a7a21434a..e1bf773b310f8d6d80a072a9af694bd50d79fe9d 100644 (file)
@@ -4,11 +4,6 @@
 #ifndef PEP384IMPL_H
 #define PEP384IMPL_H
 
-// PYSIDE-1436: Adapt to Python 3.10
-#if PY_VERSION_HEX < 0x030900A4
-#  define Py_SET_REFCNT(obj, refcnt) ((Py_REFCNT(obj) = (refcnt)), (void)0)
-#endif
-
 extern "C"
 {
 
@@ -55,46 +50,79 @@ typedef struct _typeobject {
     const char *tp_name;
     Py_ssize_t tp_basicsize;
     void *X03; // Py_ssize_t tp_itemsize;
+#ifdef PEP384_INTERN
     destructor tp_dealloc;
+#else
+    destructor X04;
+#endif
     void *X05; // Py_ssize_t tp_vectorcall_offset;
     void *X06; // getattrfunc tp_getattr;
     void *X07; // setattrfunc tp_setattr;
     void *X08; // PyAsyncMethods *tp_as_async;
+#ifdef PEP384_INTERN
     reprfunc tp_repr;
+#else
+    reprfunc X09;
+#endif
     void *X10; // PyNumberMethods *tp_as_number;
     void *X11; // PySequenceMethods *tp_as_sequence;
     void *X12; // PyMappingMethods *tp_as_mapping;
     void *X13; // hashfunc tp_hash;
+#ifdef PEP384_INTERN
     ternaryfunc tp_call;
-    reprfunc tp_str;
+#else
+    ternaryfunc X14;
+#endif
+    reprfunc tp_str; // Only used for PEP384_INTERN and a shiboken test
     getattrofunc tp_getattro;
     setattrofunc tp_setattro;
     void *X18; // PyBufferProcs *tp_as_buffer;
     unsigned long tp_flags;
     void *X20; // const char *tp_doc;
+#ifdef PEP384_INTERN
     traverseproc tp_traverse;
     inquiry tp_clear;
+#else
+    traverseproc X21;
+    inquiry X22;
+#endif
     void *X23; // richcmpfunc tp_richcompare;
     Py_ssize_t tp_weaklistoffset;
     void *X25; // getiterfunc tp_iter;
+#ifdef PEP384_INTERN
     iternextfunc tp_iternext;
+#else
+    iternextfunc X26;
+#endif
     struct PyMethodDef *tp_methods;
     struct PyMemberDef *tp_members;
     struct PyGetSetDef *tp_getset;
     struct _typeobject *tp_base;
 #ifdef PEP384_INTERN
     PyObject *tp_dict;
+    descrgetfunc tp_descr_get;
+    descrsetfunc tp_descr_set;
 #else
     void *X31;
+    descrgetfunc X32;
+    descrsetfunc X33;
 #endif
-    descrgetfunc tp_descr_get;
-    descrsetfunc tp_descr_set;
     Py_ssize_t tp_dictoffset;
+#ifdef PEP384_INTERN
     initproc tp_init;
     allocfunc tp_alloc;
+#else
+    initproc X39;
+    allocfunc X40;
+#endif
     newfunc tp_new;
+#ifdef PEP384_INTERN
     freefunc tp_free;
     inquiry tp_is_gc; /* For PyObject_IS_GC */
+#else
+    freefunc X41;
+    inquiry X42; /* For PyObject_IS_GC */
+#endif
     PyObject *tp_bases;
     PyObject *tp_mro; /* method resolution order */
 
@@ -160,6 +188,13 @@ LIBSHIBOKEN_API int Pep_GetFlag(const char *name);
 LIBSHIBOKEN_API int Pep_GetVerboseFlag(void);
 #endif
 
+// pyerrors.h
+#if defined(Py_LIMITED_API) || PY_VERSION_HEX < 0x030C0000
+LIBSHIBOKEN_API PyObject *PepErr_GetRaisedException();
+#else
+#  define PepErr_GetRaisedException PyErr_GetRaisedException
+#endif
+
 /*****************************************************************************
  *
  * RESOLVED: unicodeobject.h
@@ -396,6 +431,8 @@ LIBSHIBOKEN_API int PepCode_Check(PyObject *o);
 #  define PepCode_GET_FLAGS(o)         PepCode_Get(o, "co_flags")
 #  define PepCode_GET_ARGCOUNT(o)      PepCode_Get(o, "co_argcount")
 
+LIBSHIBOKEN_API PyObject *PepFunction_GetDefaults(PyObject *function);
+
 /* Masks for co_flags above */
 #  define CO_OPTIMIZED    0x0001
 #  define CO_NEWLOCALS    0x0002
@@ -555,6 +592,8 @@ LIBSHIBOKEN_API PyObject *PepType_GetDict(PyTypeObject *type);
 // is no longer considered to be accessible, we treat it as such.
 LIBSHIBOKEN_API int PepType_SetDict(PyTypeObject *type, PyObject *dict);
 
+LIBSHIBOKEN_API void *PepType_GetSlot(PyTypeObject *type, int aSlot);
+
 /*****************************************************************************
  *
  * Module Initialization
diff --git a/sources/shiboken6/libshiboken/pyobjectholder.h b/sources/shiboken6/libshiboken/pyobjectholder.h
new file mode 100644 (file)
index 0000000..857748c
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PYOBJECTHOLDER_H
+#define PYOBJECTHOLDER_H
+
+#include "sbkpython.h"
+
+#include <cassert>
+#include <utility>
+
+namespace Shiboken
+{
+
+/// PyObjectHolder holds a PyObject pointer, keeping a reference decrementing
+/// its reference counter when destroyed. It makes sure to hold the GIL when
+/// releasing. It implements copy/move semantics and is mainly intended as a
+/// base class for functors holding a callable which can be passed around and
+/// stored in containers or moved from freely.
+/// For one-shot functors, release() can be invoked after the call.
+class PyObjectHolder
+{
+public:
+    PyObjectHolder() noexcept = default;
+
+    /// PyObjectHolder constructor.
+    /// \param pyobj A reference to a Python object
+    explicit PyObjectHolder(PyObject *pyObj) noexcept : m_pyObj(pyObj)
+    {
+        assert(pyObj != nullptr);
+        Py_INCREF(m_pyObj);
+    }
+
+    PyObjectHolder(const PyObjectHolder &o) noexcept : m_pyObj(o.m_pyObj)
+    {
+        Py_XINCREF(m_pyObj);
+    }
+
+    PyObjectHolder &operator=(const PyObjectHolder &o) noexcept
+    {
+        if (this != &o) {
+            m_pyObj = o.m_pyObj;
+            Py_XINCREF(m_pyObj);
+        }
+        return *this;
+    }
+
+    PyObjectHolder(PyObjectHolder &&o) noexcept : m_pyObj{std::exchange(o.m_pyObj, nullptr)} {}
+
+    PyObjectHolder &operator=(PyObjectHolder &&o) noexcept
+    {
+        m_pyObj = std::exchange(o.m_pyObj, nullptr);
+        return *this;
+    }
+
+    /// Decref the python reference
+    ~PyObjectHolder() { release(); }
+
+    [[nodiscard]] bool isNull() const { return m_pyObj == nullptr; }
+    [[nodiscard]] operator bool() const { return m_pyObj != nullptr; }
+
+    /// Returns the pointer of the Python object being held.
+    [[nodiscard]] PyObject *object() const { return m_pyObj; }
+    [[nodiscard]] operator PyObject *() const { return m_pyObj; }
+
+    [[nodiscard]] PyObject *operator->() { return m_pyObj; }
+
+protected:
+    void release()
+    {
+        if (m_pyObj != nullptr) {
+            assert(Py_IsInitialized());
+            auto gstate = PyGILState_Ensure();
+            Py_DECREF(m_pyObj);
+            PyGILState_Release(gstate);
+            m_pyObj = nullptr;
+        }
+    }
+
+private:
+    PyObject *m_pyObj = nullptr;
+};
+
+} // namespace Shiboken
+
+#endif // PYOBJECTHOLDER_H
index 96faf95eeee3ebd16a210f85f1317a3ddf964b30..8ad5aadc6fa3864c00be36d6fb91ba819470af82 100644 (file)
@@ -63,7 +63,8 @@ public:
 
     static PyObject *tpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */)
     {
-        auto *me = reinterpret_cast<ShibokenContainer *>(subtype->tp_alloc(subtype, 0));
+        allocfunc allocFunc = reinterpret_cast<allocfunc>(PepType_GetSlot(subtype, Py_tp_alloc));
+        auto *me = reinterpret_cast<ShibokenContainer *>(allocFunc(subtype, 0));
         auto *d = new ShibokenSequenceContainerPrivate;
         d->m_list = new SequenceContainer;
         d->m_ownsList = true;
@@ -73,10 +74,9 @@ public:
 
     static PyObject *tpNewInvalid(PyTypeObject * /* subtype */, PyObject * /* args */, PyObject * /* kwds */)
     {
-        PyErr_Format(PyExc_NotImplementedError,
+        return PyErr_Format(PyExc_NotImplementedError,
                      "Opaque containers of type '%s' cannot be instantiated.",
                      typeid(SequenceContainer).name());
-        return nullptr;
     }
 
     static int tpInit(PyObject * /* self */, PyObject * /* args */, PyObject * /* kwds */)
@@ -91,7 +91,9 @@ public:
         if (d->m_ownsList)
             delete d->m_list;
         delete d;
-        Py_TYPE(pySelf)->tp_base->tp_free(self);
+        auto freeFunc = reinterpret_cast<freefunc>(PepType_GetSlot(Py_TYPE(pySelf)->tp_base,
+                                                                   Py_tp_free));
+        freeFunc(self);
     }
 
     static Py_ssize_t sqLen(PyObject *self)
@@ -102,10 +104,8 @@ public:
     static PyObject *sqGetItem(PyObject *self, Py_ssize_t i)
     {
         auto *d = get(self);
-        if (i < 0 || i >= Py_ssize_t(d->m_list->size())) {
-            PyErr_SetString(PyExc_IndexError, "index out of bounds");
-            return nullptr;
-        }
+        if (i < 0 || i >= Py_ssize_t(d->m_list->size()))
+            return PyErr_Format(PyExc_IndexError, "index out of bounds");
         auto it = std::cbegin(*d->m_list);
         std::advance(it, i);
         return ShibokenContainerValueConverter<value_type>::convertValueToPython(*it);
@@ -130,14 +130,10 @@ public:
     static PyObject *push_back(PyObject *self, PyObject *pyArg)
     {
         auto *d = get(self);
-        if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg)) {
-            PyErr_SetString(PyExc_TypeError, "wrong type passed to append.");
-            return nullptr;
-        }
-        if (d->m_const) {
-            PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
-            return nullptr;
-        }
+        if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg))
+            return PyErr_Format(PyExc_TypeError, "wrong type passed to append.");
+        if (d->m_const)
+            return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
 
         OptionalValue value = ShibokenContainerValueConverter<value_type>::convertValueToCpp(pyArg);
         if (!value.has_value())
@@ -149,14 +145,10 @@ public:
     static PyObject *push_front(PyObject *self, PyObject *pyArg)
     {
         auto *d = get(self);
-        if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg)) {
-            PyErr_SetString(PyExc_TypeError, "wrong type passed to append.");
-            return nullptr;
-        }
-        if (d->m_const) {
-            PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
-            return nullptr;
-        }
+        if (!ShibokenContainerValueConverter<value_type>::checkValue(pyArg))
+            return PyErr_Format(PyExc_TypeError, "wrong type passed to append.");
+        if (d->m_const)
+            return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
 
         OptionalValue value = ShibokenContainerValueConverter<value_type>::convertValueToCpp(pyArg);
         if (!value.has_value())
@@ -168,10 +160,8 @@ public:
     static PyObject *clear(PyObject *self)
     {
         auto *d = get(self);
-        if (d->m_const) {
-            PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
-            return nullptr;
-        }
+        if (d->m_const)
+            return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
 
         d->m_list->clear();
         Py_RETURN_NONE;
@@ -180,10 +170,8 @@ public:
     static PyObject *pop_back(PyObject *self)
     {
         auto *d = get(self);
-        if (d->m_const) {
-            PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
-            return nullptr;
-        }
+        if (d->m_const)
+            return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
 
         d->m_list->pop_back();
         Py_RETURN_NONE;
@@ -192,10 +180,8 @@ public:
     static PyObject *pop_front(PyObject *self)
     {
         auto *d = get(self);
-        if (d->m_const) {
-            PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
-            return nullptr;
-        }
+        if (d->m_const)
+            return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
 
         d->m_list->pop_front();
         Py_RETURN_NONE;
@@ -205,21 +191,16 @@ public:
     static PyObject *reserve(PyObject *self, PyObject *pyArg)
     {
         auto *d = get(self);
-        if (PyLong_Check(pyArg) == 0) {
-            PyErr_SetString(PyExc_TypeError, "wrong type passed to reserve().");
-            return nullptr;
-        }
-        if (d->m_const) {
-            PyErr_SetString(PyExc_TypeError, msgModifyConstContainer);
-            return nullptr;
-        }
+        if (PyLong_Check(pyArg) == 0)
+            return PyErr_Format(PyExc_TypeError, "wrong type passed to reserve().");
+        if (d->m_const)
+            return PyErr_Format(PyExc_TypeError, msgModifyConstContainer);
 
         if constexpr (ShibokenContainerHasReserve<SequenceContainer>::value) {
             const Py_ssize_t size = PyLong_AsSsize_t(pyArg);
             d->m_list->reserve(size);
         } else {
-            PyErr_SetString(PyExc_TypeError, "Container does not support reserve().");
-            return nullptr;
+            return PyErr_Format(PyExc_TypeError, "Container does not support reserve().");
         }
 
         Py_RETURN_NONE;
index 2151905150215c9cc89702f52418543a786c411e..09a21ed136292ee9e7b98cfcbb5f7d9850aca5d2 100644 (file)
@@ -4,6 +4,7 @@
 #include "sbkconverter.h"
 #include "sbkconverter_p.h"
 #include "sbkarrayconverter_p.h"
+#include "sbkmodule.h"
 #include "basewrapper_p.h"
 #include "bindingmanager.h"
 #include "autodecref.h"
@@ -12,6 +13,7 @@
 
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 
 static SbkConverter **PrimitiveTypeConverters;
 
@@ -146,6 +148,13 @@ void addPythonToCppValueConversion(PyTypeObject *type,
     addPythonToCppValueConversion(sotp->converter, pythonToCppFunc, isConvertibleToCppFunc);
 }
 
+void addPythonToCppValueConversion(Shiboken::Module::TypeInitStruct typeStruct,
+                                   PythonToCppFunc pythonToCppFunc,
+                                   IsConvertibleToCppFunc isConvertibleToCppFunc)
+{
+    addPythonToCppValueConversion(typeStruct.type, pythonToCppFunc, isConvertibleToCppFunc);
+}
+
 PyObject *pointerToPython(PyTypeObject *type, const void *cppIn)
 {
     auto *sotp = PepType_SOTP(type);
@@ -227,6 +236,11 @@ PythonToCppConversion pythonToCppPointerConversion(PyTypeObject *type, PyObject
     return {};
 }
 
+PythonToCppConversion pythonToCppPointerConversion(Module::TypeInitStruct typeStruct, PyObject *pyIn)
+{
+    return pythonToCppPointerConversion(typeStruct.type, pyIn);
+}
+
 static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn)
 {
     assert(pyIn);
@@ -409,11 +423,47 @@ void registerConverterName(SbkConverter *converter, const char *typeName)
         converters.insert(std::make_pair(typeName, converter));
 }
 
-SbkConverter *getConverter(const char *typeName)
+static std::string getRealTypeName(const std::string &typeName)
 {
-    ConvertersMap::const_iterator it = converters.find(typeName);
+    auto size = typeName.size();
+    if (std::isalnum(typeName[size - 1]) == 0)
+        return typeName.substr(0, size - 1);
+    return typeName;
+}
+
+// PYSIDE-2404: Build a negative cache of already failed lookups.
+//              The resulting list must be reset after each new import,
+//              because that can change results. Also clear the cache after
+//              reaching some threashold.
+static std::unordered_set<std::string> nonExistingTypeNames{};
+
+// Arbitrary size limit to prevent random name overflows.
+static constexpr std::size_t negativeCacheLimit = 50;
+
+static void rememberAsNonexistent(const std::string &typeName)
+{
+    if (nonExistingTypeNames.size() > negativeCacheLimit)
+        clearNegativeLazyCache();
+    converters.insert(std::make_pair(typeName, nullptr));
+    nonExistingTypeNames.insert(typeName);
+}
+
+SbkConverter *getConverter(const char *typeNameC)
+{
+    std::string typeName = typeNameC;
+    auto it = converters.find(typeName);
+    // PYSIDE-2404: This can also contain explicit nullptr as a negative cache.
+    if (it != converters.end())
+        return it->second;
+    // PYSIDE-2404: Did not find the name. Load the lazy classes
+    //              which have this name and try again.
+    Shiboken::Module::loadLazyClassesWithName(getRealTypeName(typeName).c_str());
+    it = converters.find(typeName);
     if (it != converters.end())
         return it->second;
+    // Cache the negative result. Don't forget to clear the cache for new modules.
+    rememberAsNonexistent(typeName);
+
     if (Shiboken::pyVerbose() > 0) {
         const std::string message =
             std::string("Can't find type resolver for type '") + typeName + "'.";
@@ -422,6 +472,15 @@ SbkConverter *getConverter(const char *typeName)
     return nullptr;
 }
 
+void clearNegativeLazyCache()
+{
+    for (const auto &typeName : nonExistingTypeNames) {
+        auto it = converters.find(typeName);
+        converters.erase(it);
+    }
+    nonExistingTypeNames.clear();
+}
+
 SbkConverter *primitiveTypeConverter(int index)
 {
     return PrimitiveTypeConverters[index];
index 539e3286f2c047700b117cb0f34b3b83afd0a897..0d68f3fafa1396ae06e5fbeb205f78b315b8c0fe 100644 (file)
@@ -5,6 +5,7 @@
 #define SBK_CONVERTER_H
 
 #include "sbkpython.h"
+#include "sbkmodule.h"
 #include "shibokenmacros.h"
 #include "sbkenum.h"
 #include "basewrapper_p.h"
@@ -146,6 +147,9 @@ LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkConverter *converter,
 LIBSHIBOKEN_API void addPythonToCppValueConversion(PyTypeObject *type,
                                                    PythonToCppFunc pythonToCppFunc,
                                                    IsConvertibleToCppFunc isConvertibleToCppFunc);
+LIBSHIBOKEN_API void addPythonToCppValueConversion(Shiboken::Module::TypeInitStruct typeStruct,
+                                                   PythonToCppFunc pythonToCppFunc,
+                                                   IsConvertibleToCppFunc isConvertibleToCppFunc);
 
 // C++ -> Python ---------------------------------------------------------------------------
 
@@ -203,6 +207,7 @@ struct PythonToCppConversion
  */
 LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(PyTypeObject *type, PyObject *pyIn);
 LIBSHIBOKEN_API PythonToCppConversion pythonToCppPointerConversion(PyTypeObject *type, PyObject *pyIn);
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppPointerConversion(Module::TypeInitStruct typeStruct, PyObject *pyIn);
 
 /**
  *  Returns a Python to C++ conversion function if the Python object is convertible to a C++ value.
index fbb124803b0a6d8317e75362ef14b73aae6824cf..9b2d5dbabb00e02350dbb179a9893a5323779d6f 100644 (file)
@@ -327,7 +327,7 @@ struct FloatPrimitive : TwoPrimitive<FLOAT>
     }
     static void toCpp(PyObject *pyIn, void *cppOut)
     {
-        *reinterpret_cast<FLOAT *>(cppOut) = FLOAT(PyLong_AsLongLong(pyIn));
+        *reinterpret_cast<FLOAT *>(cppOut) = FLOAT(PyLong_AsDouble(pyIn));
     }
     static PythonToCppFunc isConvertible(PyObject *pyIn)
     {
@@ -531,6 +531,10 @@ SbkConverter *createConverterObject(PyTypeObject *type,
                                     IsConvertibleToCppFunc toCppPointerCheckFunc,
                                     CppToPythonFunc pointerToPythonFunc,
                                     CppToPythonFunc copyToPythonFunc);
+
+/// Interface for sbkmodule which must reset cache when new module is loaded.
+LIBSHIBOKEN_API void clearNegativeLazyCache();
+
 } // namespace Shiboken::Conversions
 
 #endif // SBK_CONVERTER_P_H
index 42b09111c01f725531b4f9bd0f0c439f617084df..8e8324f5ef50d40c9c7aeda3475f5d93b479753f 100644 (file)
@@ -12,6 +12,11 @@ PyObject *fromCppString(const std::string &value)
     return PyUnicode_FromStringAndSize(value.data(), value.size());
 }
 
+PyObject *fromCppStringView(std::string_view value)
+{
+    return PyUnicode_FromStringAndSize(value.data(), value.size());
+}
+
 PyObject *fromCppWString(const std::wstring &value)
 {
     return PyUnicode_FromWideChar(value.data(), value.size());
index f418ea8dd5f0310d6b293d86267a50422ee3ca8d..7ffe11c758a66c8e0f7fb5ce245c1f1d8ae9e2a5 100644 (file)
@@ -8,10 +8,12 @@
 #include "shibokenmacros.h"
 
 #include <string>
+#include <string_view>
 
 namespace Shiboken::String
 {
     LIBSHIBOKEN_API PyObject *fromCppString(const std::string &value);
+    LIBSHIBOKEN_API PyObject *fromCppStringView(std::string_view value);
     LIBSHIBOKEN_API PyObject *fromCppWString(const std::wstring &value);
     LIBSHIBOKEN_API void toCppString(PyObject *str, std::string *value);
     LIBSHIBOKEN_API void toCppWString(PyObject *str, std::wstring *value);
index 44e900f019a0b540060146fb286d20c49cbac2f9..7637efa70e7c7c4f6d775321a6244fe6968b08df 100644 (file)
@@ -49,17 +49,17 @@ PyObject *createByteArray1(Py_ssize_t, const uint8_t *)
 
 PyObject *createDoubleArray1(Py_ssize_t, const double *)
 {
-    return Py_None;
+    Py_RETURN_NONE;
 }
 
 PyObject *createFloatArray1(Py_ssize_t, const float *)
 {
-    return Py_None;
+    Py_RETURN_NONE;
 }
 
 PyObject *createIntArray1(Py_ssize_t, const int *)
 {
-    return Py_None;
+    Py_RETURN_NONE;
 }
 
 #endif // !HAVE_NUMPY
index d39369979a716e6a50c2d6d6bc508cada7691e3a..4c0597bda4fa21359f3829da7ec1cf4de730d91c 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "sbkenum.h"
 #include "sbkstring.h"
+#include "helper.h"
 #include "sbkstaticstrings.h"
 #include "sbkstaticstrings_p.h"
 #include "sbkconverter.h"
@@ -306,6 +307,8 @@ static PyTypeObject *createEnumForPython(PyObject *scopeOrModule,
         enumName = PyDict_GetItem(sotp->enumTypeDict, name);
     }
 
+    SBK_UNUSED(getPyEnumMeta()); // enforce PyEnumModule creation
+    assert(PyEnumModule != nullptr);
     AutoDecRef PyEnumType(PyObject_GetAttr(PyEnumModule, enumName));
     assert(PyEnumType.object());
     bool isFlag = PyObject_IsSubclass(PyEnumType, PyFlag);
index 906df8e1952d3fceedb16dc7ba4080a507bcc167..f31b8f4f7f430dfecbee26fdadd18c8207a8958b 100644 (file)
@@ -4,6 +4,7 @@
 #include "basewrapper.h"
 #include "basewrapper_p.h"
 #include "autodecref.h"
+#include "pep384ext.h"
 #include "sbkenum.h"
 #include "sbkstring.h"
 #include "sbkstaticstrings.h"
@@ -37,11 +38,19 @@ int currentSelectId(PyTypeObject *type)
 }
 
 static SelectableFeatureHook SelectFeatureSet = nullptr;
+static SelectableFeatureCallback featureCb = nullptr;
+
+void setSelectableFeatureCallback(SelectableFeatureCallback func)
+{
+    featureCb = func;
+}
 
 SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func)
 {
     auto ret = SelectFeatureSet;
     SelectFeatureSet = func;
+    if (featureCb)
+        featureCb(SelectFeatureSet != nullptr);
     return ret;
 }
 //
@@ -56,14 +65,24 @@ void disassembleFrame(const char *marker)
     static PyObject *dismodule = PyImport_ImportModule("dis");
     static PyObject *disco = PyObject_GetAttrString(dismodule, "disco");
     static PyObject *const _f_lasti = Shiboken::String::createStaticString("f_lasti");
+    static PyObject *const _f_lineno = Shiboken::String::createStaticString("f_lineno");
     static PyObject *const _f_code = Shiboken::String::createStaticString("f_code");
-    auto *frame = reinterpret_cast<PyObject *>(PyEval_GetFrame());
-    AutoDecRef f_lasti(PyObject_GetAttr(frame, _f_lasti));
-    AutoDecRef f_code(PyObject_GetAttr(frame, _f_code));
+    static PyObject *const _co_filename = Shiboken::String::createStaticString("co_filename");
     AutoDecRef ignore{};
-    fprintf(stdout, "\n%s BEGIN\n", marker);
-    ignore.reset(PyObject_CallFunctionObjArgs(disco, f_code.object(), f_lasti.object(), nullptr));
-    fprintf(stdout, "%s END\n\n", marker);
+    auto *frame = reinterpret_cast<PyObject *>(PyEval_GetFrame());
+    if (frame == nullptr) {
+        fprintf(stdout, "\n%s BEGIN no frame END\n\n", marker);
+    } else {
+        AutoDecRef f_lasti(PyObject_GetAttr(frame, _f_lasti));
+        AutoDecRef f_lineno(PyObject_GetAttr(frame, _f_lineno));
+        AutoDecRef f_code(PyObject_GetAttr(frame, _f_code));
+        AutoDecRef co_filename(PyObject_GetAttr(f_code, _co_filename));
+        long line = PyLong_AsLong(f_lineno);
+        const char *fname = String::toCString(co_filename);
+        fprintf(stdout, "\n%s BEGIN line=%ld %s\n", marker, line, fname);
+        ignore.reset(PyObject_CallFunctionObjArgs(disco, f_code.object(), f_lasti.object(), nullptr));
+        fprintf(stdout, "%s END line=%ld %s\n\n", marker, line, fname);
+    }
 #if PY_VERSION_HEX >= 0x030C0000 && !Py_LIMITED_API
     if (error_type)
         PyErr_DisplayException(error_value);
@@ -101,7 +120,7 @@ static bool currentOpcode_Is_CallMethNoArgs()
     // We look into the currently active operation if we are going to call
     // a method with zero arguments.
     auto *frame = PyEval_GetFrame();
-#if PY_VERSION_HEX >= 0x03090000 && !Py_LIMITED_API && !defined(PYPY_VERSION)
+#if !Py_LIMITED_API && !defined(PYPY_VERSION)
     auto *f_code = PyFrame_GetCode(frame);
 #else
     static PyObject *const _f_code = Shiboken::String::createStaticString("f_code");
@@ -300,7 +319,7 @@ PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name)
      * with the complex `tp_getattro` of `QObject` and other instances.
      * What we change here is the meta class of `QObject`.
      */
-    static getattrofunc const type_getattro = PyType_Type.tp_getattro;
+    static getattrofunc const type_getattro = PepExt_Type_GetGetAttroSlot(&PyType_Type);
     static PyObject *const ignAttr1 = PyName::qtStaticMetaObject();
     static PyObject *const ignAttr2 = PyMagicName::get();
     static PyTypeObject *const EnumMeta = getPyEnumMeta();
index aeae34a36fb8ee57c73ea68238de26a5be6ed7b1..adcd675616622a6ecc45138eb2e6d51fee9baf82 100644 (file)
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "sbkmodule.h"
+#include "autodecref.h"
 #include "basewrapper.h"
 #include "bindingmanager.h"
+#include "sbkstring.h"
+#include "sbkcppstring.h"
+#include "sbkconverter_p.h"
+
 #include <unordered_map>
+#include <unordered_set>
+#include <cstring>
 
 /// This hash maps module objects to arrays of Python types.
-using ModuleTypesMap = std::unordered_map<PyObject *, PyTypeObject **> ;
+using ModuleTypesMap = std::unordered_map<PyObject *, Shiboken::Module::TypeInitStruct *> ;
 
 /// This hash maps module objects to arrays of converters.
 using ModuleConvertersMap = std::unordered_map<PyObject *, SbkConverter **>;
 
+/// This hash maps type names to type creation functions.
+using TypeCreationFunctionModulePair =
+    std::pair<Shiboken::Module::TypeCreationFunction, PyObject *>;
+using NameToTypeFunctionMap = std::unordered_map<std::string, TypeCreationFunctionModulePair>;
+
+/// This hash maps module objects to maps of names to functions.
+using ModuleToFuncsMap = std::unordered_map<PyObject *, NameToTypeFunctionMap> ;
+
 /// All types produced in imported modules are mapped here.
 static ModuleTypesMap moduleTypes;
 static ModuleConvertersMap moduleConverters;
+static ModuleToFuncsMap moduleToFuncs;
 
 namespace Shiboken
 {
 namespace Module
 {
 
+// PYSIDE-2404: Replacing the arguments generated by cpythonTypeNameExt
+//              by a function call.
+LIBSHIBOKEN_API PyTypeObject *get(TypeInitStruct &typeStruct)
+{
+    if (typeStruct.type != nullptr)
+        return typeStruct.type;
+
+    static PyObject *sysModules = PyImport_GetModuleDict();
+
+    // The slow path for initialization.
+    // We get the type by following the chain from the module.
+    // As soon as types[index] gets filled, we can stop.
+
+    std::string_view names(typeStruct.fullName);
+    const bool usePySide = names.compare(0, 8, "PySide6.") == 0;
+    auto dotPos = usePySide ? names.find('.', 8) : names.find('.');
+    auto startPos = dotPos + 1;
+    AutoDecRef modName(String::fromCppStringView(names.substr(0, dotPos)));
+    auto *modOrType = PyDict_GetItem(sysModules, modName);
+    if (modOrType == nullptr) {
+        PyErr_Format(PyExc_SystemError, "Module \"%U\" should already be in sys.modules",
+                                        modName.object());
+        return nullptr;
+    }
+
+    do {
+        dotPos = names.find('.', startPos);
+        auto typeName = dotPos != std::string::npos
+                        ? names.substr(startPos, dotPos - startPos)
+                        : names.substr(startPos);
+        startPos = dotPos + 1;
+        AutoDecRef obTypeName(String::fromCppStringView(typeName));
+        modOrType = PyObject_GetAttr(modOrType, obTypeName);
+    } while (typeStruct.type == nullptr && dotPos != std::string::npos);
+
+    return typeStruct.type;
+}
+
+static PyTypeObject *incarnateType(PyObject *module, const char *name,
+                                   NameToTypeFunctionMap &nameToFunc)
+{
+    // - locate the name and retrieve the generating function
+    auto funcIter = nameToFunc.find(name);
+    if (funcIter == nameToFunc.end()) {
+        // attribute does really not exist.
+        PyErr_SetNone(PyExc_AttributeError);
+        return nullptr;
+    }
+    // - call this function that returns a PyTypeObject
+    auto pair = funcIter->second;
+    auto initFunc = pair.first;
+    auto *modOrType = pair.second;
+
+    // PYSIDE-2404: Make sure that no switching happens during type creation.
+    auto saveFeature = initSelectableFeature(nullptr);
+    PyTypeObject *type = initFunc(modOrType);
+    initSelectableFeature(saveFeature);
+
+    // - assign this object to the name in the module
+    auto *res = reinterpret_cast<PyObject *>(type);
+    Py_INCREF(res);
+    PyModule_AddObject(module, name, res);   // steals reference
+    // - remove the entry, if not by something cleared.
+    if (!nameToFunc.empty())
+        nameToFunc.erase(funcIter);
+    // - return the PyTypeObject.
+    return type;
+}
+
+// PYSIDE-2404: Make sure that the mentioned classes really exist.
+// Used in `Pyside::typeName`. Because the result will be cached by
+// the creation of the type(s), this is efficient.
+void loadLazyClassesWithName(const char *name)
+{
+    for (auto const & tableIter : moduleToFuncs) {
+        auto nameToFunc = tableIter.second;
+        auto funcIter = nameToFunc.find(name);
+        if (funcIter != nameToFunc.end()) {
+            // attribute exists in the lazy types.
+            auto *module = tableIter.first;
+            incarnateType(module, name, nameToFunc);
+        }
+    }
+}
+
+// PYSIDE-2404: Completely load all not yet loaded classes.
+//              This is needed to resolve a star import.
+void resolveLazyClasses(PyObject *module)
+{
+    // - locate the module in the moduleTofuncs mapping
+    auto tableIter = moduleToFuncs.find(module);
+    if (tableIter == moduleToFuncs.end())
+        return;
+
+    // - see if there are still unloaded elements
+    auto &nameToFunc = tableIter->second;
+
+    // - incarnate all types.
+    while (!nameToFunc.empty()) {
+        auto it = nameToFunc.begin();
+        auto attrNameStr = it->first;
+        incarnateType(module, attrNameStr.c_str(), nameToFunc);
+    }
+}
+
+// PYSIDE-2404: Override the gettattr function of modules.
+static getattrofunc origModuleGetattro{};
+
+// PYSIDE-2404: Use the patched module getattr to do on-demand initialization.
+//              This modifies _all_ modules but should have no impact.
+static PyObject *PyModule_lazyGetAttro(PyObject *module, PyObject *name)
+{
+    // - check if the attribute is present and return it.
+    auto *attr = PyObject_GenericGetAttr(module, name);
+    // - we handle AttributeError, only.
+    if (!(attr == nullptr && PyErr_ExceptionMatches(PyExc_AttributeError)))
+        return attr;
+
+    PyErr_Clear();
+    // - locate the module in the moduleTofuncs mapping
+    auto tableIter = moduleToFuncs.find(module);
+    // - if this is not our module, use the original
+    if (tableIter == moduleToFuncs.end())
+        return origModuleGetattro(module, name);
+
+    // - locate the name and retrieve the generating function
+    const char *attrNameStr = Shiboken::String::toCString(name);
+    auto &nameToFunc = tableIter->second;
+    // - create the real type (incarnateType checks this)
+    auto *type = incarnateType(module, attrNameStr, nameToFunc);
+    auto *ret = reinterpret_cast<PyObject *>(type);
+    // - if attribute does really not exist use the original
+    if (ret == nullptr && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+        PyErr_Clear();
+        return origModuleGetattro(module, name);
+    }
+
+    return ret;
+}
+
+// PYSIDE-2404: Supply a new module dir for not yet visible entries.
+//              This modification is only for "our" modules.
+static PyObject *_module_dir_template(PyObject * /* self */, PyObject *args)
+{
+    static PyObject *const _dict = Shiboken::String::createStaticString("__dict__");
+    // The dir function must replace all of the builtin function.
+    PyObject *module{};
+    if (!PyArg_ParseTuple(args, "O", &module))
+        return nullptr;
+
+    auto tableIter = moduleToFuncs.find(module);
+    assert(tableIter != moduleToFuncs.end());
+    Shiboken::AutoDecRef dict(PyObject_GetAttr(module, _dict));
+    auto *ret = PyDict_Keys(dict);
+    // Now add all elements that were not yet in the dict.
+    auto &nameToFunc = tableIter->second;
+    for (const auto &funcIter : nameToFunc) {
+        const char *name = funcIter.first.c_str();
+        Shiboken::AutoDecRef pyName(PyUnicode_FromString(name));
+        PyList_Append(ret, pyName);
+    }
+    return ret;
+}
+
+static PyMethodDef module_methods[] = {
+    {"__dir__", (PyCFunction)_module_dir_template, METH_VARARGS, nullptr},
+    {nullptr, nullptr, 0, nullptr}
+};
+
+// Python 3.8 - 3.12
+static int const LOAD_CONST_312 = 100;
+static int const IMPORT_NAME_312 = 108;
+
+static bool isImportStar(PyObject *module)
+{
+    // Find out whether we have a star import. This must work even
+    // when we have no import support from feature.
+    static PyObject *const _f_code = Shiboken::String::createStaticString("f_code");
+    static PyObject *const _f_lasti = Shiboken::String::createStaticString("f_lasti");
+    static PyObject *const _f_back = Shiboken::String::createStaticString("f_back");
+    static PyObject *const _co_code = Shiboken::String::createStaticString("co_code");
+    static PyObject *const _co_consts = Shiboken::String::createStaticString("co_consts");
+    static PyObject *const _co_names = Shiboken::String::createStaticString("co_names");
+
+    auto *obFrame = reinterpret_cast<PyObject *>(PyEval_GetFrame());
+    if (obFrame == nullptr)
+        return true;            // better assume worst-case.
+
+    Py_INCREF(obFrame);
+    AutoDecRef dec_frame(obFrame);
+
+    // Calculate the offset of the running import_name opcode on the stack.
+    // Right before that there must be a load_const with the tuple `("*",)`.
+    while (dec_frame.object() != Py_None) {
+        AutoDecRef dec_f_code(PyObject_GetAttr(dec_frame, _f_code));
+        AutoDecRef dec_co_code(PyObject_GetAttr(dec_f_code, _co_code));
+        AutoDecRef dec_f_lasti(PyObject_GetAttr(dec_frame, _f_lasti));
+        Py_ssize_t f_lasti = PyLong_AsSsize_t(dec_f_lasti);
+        Py_ssize_t code_len;
+        char *co_code{};
+        PyBytes_AsStringAndSize(dec_co_code, &co_code, &code_len);
+        uint8_t opcode2 = co_code[f_lasti];
+        uint8_t opcode1 = co_code[f_lasti - 2];
+        if (opcode1 == LOAD_CONST_312 && opcode2 == IMPORT_NAME_312) {
+            uint8_t oparg1 = co_code[f_lasti - 1];
+            uint8_t oparg2 = co_code[f_lasti + 1];
+            AutoDecRef dec_co_consts(PyObject_GetAttr(dec_f_code, _co_consts));
+            auto *fromlist = PyTuple_GetItem(dec_co_consts, oparg1);
+            if (PyTuple_Check(fromlist) && PyTuple_Size(fromlist) == 1
+                    && Shiboken::String::toCString(PyTuple_GetItem(fromlist, 0))[0] == '*') {
+                AutoDecRef dec_co_names(PyObject_GetAttr(dec_f_code, _co_names));
+                const char *name = String::toCString(PyTuple_GetItem(dec_co_names, oparg2));
+                const char *modName = PyModule_GetName(module);
+                if (std::strcmp(name, modName) == 0)
+                    return true;
+            }
+        }
+        dec_frame.reset(PyObject_GetAttr(dec_frame, _f_back));
+    }
+    return false;
+}
+
+// PYSIDE-2404: These modules produce ambiguous names which we cannot handle, yet.
+static std::unordered_set<std::string> dontLazyLoad{
+    "sample",
+    "smart",
+    "testbinding"
+};
+
+static const std::unordered_set<std::string> knownModules{
+    "shiboken6.Shiboken",
+    "minimal",
+    "other",
+    "sample",
+    "smart",
+    "scriptableapplication",
+    "testbinding"
+};
+
+static bool canNotLazyLoad(PyObject *module)
+{
+    const char *modName = PyModule_GetName(module);
+
+    // There are no more things that must be disabled :-D
+    return dontLazyLoad.find(modName) != dontLazyLoad.end();
+}
+
+static bool shouldLazyLoad(PyObject *module)
+{
+    const char *modName = PyModule_GetName(module);
+
+    if (knownModules.find(modName) != knownModules.end())
+        return true;
+    return std::strncmp(modName, "PySide6.", 8) == 0;
+}
+
+static int lazyLoadDefault()
+{
+#ifndef PYPY_VERSION
+    int result = 1;
+#else
+    int result = 0;
+#endif
+    if (auto *flag = getenv("PYSIDE6_OPTION_LAZY"))
+        result = std::atoi(flag);
+    return result;
+}
+
+void AddTypeCreationFunction(PyObject *module,
+                             const char *name,
+                             TypeCreationFunction func)
+{
+    static const int value = lazyLoadDefault();
+
+    // - locate the module in the moduleTofuncs mapping
+    auto tableIter = moduleToFuncs.find(module);
+    assert(tableIter != moduleToFuncs.end());
+    // - Assign the name/generating function pair.
+    auto &nameToFunc = tableIter->second;
+    TypeCreationFunctionModulePair pair{func, module};
+    auto nit = nameToFunc.find(name);
+    if (nit == nameToFunc.end())
+        nameToFunc.insert(std::make_pair(name, pair));
+    else
+        nit->second = pair;
+
+    // PYSIDE-2404: Lazy Loading
+    //
+    // Options:
+    //   0  - switch lazy loading off.
+    //   1  - lazy loading for all known modules.
+    //   3  - lazy loading for any module.
+    //
+    // By default we lazy load all known modules (option = 1).
+
+    if (value == 0                                  // completely disabled
+        || canNotLazyLoad(module)                   // for some reason we cannot lazy load
+        || (value == 1 && !shouldLazyLoad(module))  // not a known module
+        ) {
+        PyTypeObject *type = func(module);
+        PyModule_AddObject(module, name, reinterpret_cast<PyObject *>(type));   // steals reference
+    }
+}
+
+void AddTypeCreationFunction(PyObject *module,
+                             const char *name,
+                             TypeCreationFunction func,
+                             const char *containerName)
+{
+    // This version could be delayed as well, but for the few cases
+    // we simply fetch the container type and insert directly.
+    AutoDecRef obContainerType(PyObject_GetAttrString(module, containerName));
+    PyTypeObject *type = func(obContainerType);
+    PyObject_SetAttrString(obContainerType, name, reinterpret_cast<PyObject *>(type));   // steals reference
+}
+
+void AddTypeCreationFunction(PyObject *module,
+                             const char *name,
+                             TypeCreationFunction func,
+                             const char *outerContainerName,
+                             const char *innerContainerName)
+{
+    // This version has even more indirection. It is very rare, and
+    // we handle it directly.
+    AutoDecRef obOuterType(PyObject_GetAttrString(module, outerContainerName));
+    AutoDecRef obInnerType(PyObject_GetAttrString(obOuterType, innerContainerName));
+    PyTypeObject *type = func(obInnerType);
+    PyObject_SetAttrString(obInnerType, name, reinterpret_cast<PyObject *>(type));   // steals reference
+}
+
+void AddTypeCreationFunction(PyObject *module,
+                             const char *name,
+                             TypeCreationFunction func,
+                             const char *containerName3,
+                             const char *containerName2,
+                             const char *containerName)
+{
+    // This version has even mode indirection. It is very rare, and
+    // we handle it directly.
+    AutoDecRef obContainerType3(PyObject_GetAttrString(module, containerName3));
+    AutoDecRef obContainerType2(PyObject_GetAttrString(obContainerType3, containerName2));
+    AutoDecRef obContainerType(PyObject_GetAttrString(obContainerType2, containerName));
+    PyTypeObject *type = func(obContainerType);
+    PyObject_SetAttrString(obContainerType, name, reinterpret_cast<PyObject *>(type));   // steals reference
+}
+
 PyObject *import(const char *moduleName)
 {
     PyObject *sysModules = PyImport_GetModuleDict();
     PyObject *module = PyDict_GetItemString(sysModules, moduleName);
-    if (module)
+    if (module != nullptr)
         Py_INCREF(module);
     else
         module = PyImport_ImportModule(moduleName);
 
-    if (!module)
-        PyErr_Format(PyExc_ImportError,"could not import module '%s'", moduleName);
+    if (module == nullptr)
+        PyErr_Format(PyExc_ImportError, "could not import module '%s'", moduleName);
 
     return module;
 }
 
-PyObject *create(const char * /* moduleName */, void *moduleData)
+// PYSIDE-2404: Redirecting import for "import *" support.
+//
+// The first import will be handled by the isImportStar function.
+// But the same module might be imported twice, which would give no
+// introspection due to module caching.
+
+static PyObject *origImportFunc{};
+
+static PyObject *lazy_import(PyObject * /* self */, PyObject *args, PyObject *kwds)
+{
+    auto *ret = PyObject_Call(origImportFunc, args, kwds);
+    if (ret != nullptr) {
+        // PYSIDE-2404: Support star import when lazy loading.
+        if (PyTuple_Size(args) >= 4) {
+            auto *fromlist = PyTuple_GetItem(args, 3);
+            if (PyTuple_Check(fromlist) && PyTuple_Size(fromlist) == 1
+                    && Shiboken::String::toCString(PyTuple_GetItem(fromlist, 0))[0] == '*')
+                Shiboken::Module::resolveLazyClasses(ret);
+        }
+    }
+    return ret;
+}
+
+static PyMethodDef lazy_methods[] = {
+    {"__lazy_import__", (PyCFunction)lazy_import, METH_VARARGS | METH_KEYWORDS, nullptr},
+    {nullptr, nullptr, 0, nullptr}
+};
+
+PyObject *create(const char * /* modName */, void *moduleData)
 {
+    static auto *sysModules = PyImport_GetModuleDict();
+    static auto *builtins = PyEval_GetBuiltins();
+    static auto *partial = Pep_GetPartialFunction();
+    static bool lazy_init{};
+
     Shiboken::init();
-    return PyModule_Create(reinterpret_cast<PyModuleDef *>(moduleData));
+    auto *module = PyModule_Create(reinterpret_cast<PyModuleDef *>(moduleData));
+
+    // Setup of a dir function for "missing" classes.
+    auto *moduleDirTemplate = PyCFunction_NewEx(module_methods, nullptr, nullptr);
+    // Turn this function into a bound object, so we have access to the module.
+    auto *moduleDir = PyObject_CallFunctionObjArgs(partial, moduleDirTemplate, module, nullptr);
+    PyModule_AddObject(module, module_methods->ml_name, moduleDir);  // steals reference
+    // Insert an initial empty table for the module.
+    NameToTypeFunctionMap empty;
+    moduleToFuncs.insert(std::make_pair(module, empty));
+
+    // A star import must be done unconditionally. Use the complete name.
+    if (isImportStar(module))
+        dontLazyLoad.insert(PyModule_GetName(module));
+
+    if (!lazy_init) {
+        // Install the getattr patch.
+        origModuleGetattro = PyModule_Type.tp_getattro;
+        PyModule_Type.tp_getattro = PyModule_lazyGetAttro;
+        // Add the lazy import redirection, keeping a reference.
+        origImportFunc = PyDict_GetItemString(builtins, "__import__");
+        Py_INCREF(origImportFunc);
+        AutoDecRef func(PyCFunction_NewEx(lazy_methods, nullptr, nullptr));
+        PyDict_SetItemString(builtins, "__import__", func);
+        // Everything is set.
+        lazy_init = true;
+    }
+    // PYSIDE-2404: Nuitka inserts some additional code in standalone mode
+    //              in an invisible virtual module (i.e. `QtCore-postLoad`)
+    //              that gets imported before the running import can call
+    //              `_PyImport_FixupExtensionObject` which does the insertion
+    //              into `sys.modules`. This can cause a race condition.
+    // Insert the module early into the module dict to prevend recursion.
+    PyDict_SetItemString(sysModules, PyModule_GetName(module), module);
+    // Clear the non-existing name cache because we have a new module.
+    Shiboken::Conversions::clearNegativeLazyCache();
+    return module;
 }
 
-void registerTypes(PyObject *module, PyTypeObject **types)
+void registerTypes(PyObject *module, TypeInitStruct *types)
 {
     auto iter = moduleTypes.find(module);
     if (iter == moduleTypes.end())
         moduleTypes.insert(std::make_pair(module, types));
 }
 
-PyTypeObject **getTypes(PyObject *module)
+TypeInitStruct *getTypes(PyObject *module)
 {
     auto iter = moduleTypes.find(module);
     return (iter == moduleTypes.end()) ? 0 : iter->second;
index c39692f174ea39af973703b985527d6d8619636e..1b3de33b736e2f83d78744f7e4aed68a3f4a1b42 100644 (file)
@@ -14,6 +14,21 @@ struct SbkConverter;
 
 namespace Shiboken::Module {
 
+struct TypeInitStruct
+{
+    PyTypeObject *type;
+    const char *fullName;
+};
+
+/// PYSIDE-2404: Replacing the arguments in cpythonTypeNameExt by a function.
+LIBSHIBOKEN_API PyTypeObject *get(TypeInitStruct &typeStruct);
+
+/// PYSIDE-2404: Make sure that mentioned classes really exist.
+LIBSHIBOKEN_API void loadLazyClassesWithName(const char *name);
+
+/// PYSIDE-2404: incarnate all classes for star imports.
+LIBSHIBOKEN_API void resolveLazyClasses(PyObject *module);
+
 /**
  *  Imports and returns the module named \p moduleName, or a NULL pointer in case of failure.
  *  If the module is already imported, it increments its reference count before returning it.
@@ -29,19 +44,43 @@ LIBSHIBOKEN_API PyObject *import(const char *moduleName);
  */
 LIBSHIBOKEN_API PyObject *create(const char *moduleName, void *moduleData);
 
+using TypeCreationFunction = PyTypeObject *(*)(PyObject *module);
+
+/// Adds a type creation function to the module.
+LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
+                                             const char *name,
+                                             TypeCreationFunction func);
+
+LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
+                                             const char *name,
+                                             TypeCreationFunction func,
+                                             const char *containerName);
+
+LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
+                                             const char *name,
+                                             TypeCreationFunction func,
+                                             const char *outerContainerName,
+                                             const char *innerContainerName);
+
+LIBSHIBOKEN_API void AddTypeCreationFunction(PyObject *module,
+                                             const char *name,
+                                             TypeCreationFunction func,
+                                             const char *containerName3,
+                                             const char *containerName2,
+                                             const char *containerName);
 /**
  *  Registers the list of types created by \p module.
  *  \param module   Module where the types were created.
  *  \param types    Array of PyTypeObject *objects representing the types created on \p module.
  */
-LIBSHIBOKEN_API void registerTypes(PyObject *module, PyTypeObject **types);
+LIBSHIBOKEN_API void registerTypes(PyObject *module, TypeInitStruct *types);
 
 /**
  *  Retrieves the array of types.
  *  \param module   Module where the types were created.
  *  \returns        A pointer to the PyTypeObject *array of types.
  */
-LIBSHIBOKEN_API PyTypeObject **getTypes(PyObject *module);
+LIBSHIBOKEN_API TypeInitStruct *getTypes(PyObject *module);
 
 /**
  *  Registers the list of converters created by \p module for non-wrapper types.
index 060a2b6f480583f58880197c9e2dd878eca53aa2..b6422e73f4d7e103cc54d1a24dca80f12ca81a79 100644 (file)
 namespace Shiboken::Numpy
 {
 
+#ifdef HAVE_NUMPY
+static void initNumPy()
+{
+    // PYSIDE-2404: Delay-initialize numpy from check() as it causes a
+    // significant startup delay (~770 allocations in memray)
+    static bool initialized = false;
+    if (initialized)
+        return;
+    initialized = true;
+    // Expanded from macro "import_array" in __multiarray_api.h
+    // Make sure to read about the magic defines PY_ARRAY_UNIQUE_SYMBOL etc.,
+    // when changing this or spreading the code over several source files.
+    if (_import_array() < 0)
+        PyErr_Print();
+}
+#endif // HAVE_NUMPY
+
 bool check(PyObject *pyIn)
 {
 #ifdef HAVE_NUMPY
+    initNumPy();
     return PyArray_Check(pyIn);
 #else
     SBK_UNUSED(pyIn);
index e71fe9d686207085a3dec68a34127f5111d80c49..835a97524414ab768173056f3c0c90c87bf473ec 100644 (file)
@@ -104,6 +104,7 @@ SbkArrayConverter *unimplementedArrayConverter();
 template <int dimension>
 static bool isPrimitiveArray(PyObject *pyIn, int expectedNpType)
 {
+    Shiboken::Numpy::initNumPy();
     if (!PyArray_Check(pyIn))
         return false;
     auto *pya = reinterpret_cast<PyArrayObject *>(pyIn);
@@ -209,6 +210,9 @@ static PythonToCppFunc checkArray2(PyObject *pyIn, int dim1, int dim2)
 template <class T>
 static void setOrExtendArrayConverter(int dimension, IsArrayConvertibleToCppFunc toCppCheckFunc)
 {
+    // PYSIDE-2404/FIXME: When adding a C++ -> Python conversion, be sure
+    // to delay-initialize numpy in the converter (similar to the
+    // initialization in check() for the Python -> C++ conversion).
     SbkArrayConverter *arrayConverter = ArrayTypeConverter<T>(dimension);
     if (arrayConverter == unimplementedArrayConverter()) {
         arrayConverter = createArrayConverter(toCppCheckFunc);
@@ -234,15 +238,6 @@ static inline void extendArrayConverter2()
 
 void initNumPyArrayConverters()
 {
-    // Expanded from macro "import_array" in __multiarray_api.h
-    // Make sure to read about the magic defines PY_ARRAY_UNIQUE_SYMBOL etc.,
-    // when changing this or spreading the code over several source files.
-    if (_import_array() < 0) {
-        if (debugNumPy)
-            PyErr_Print();
-        PyErr_Clear();
-        return;
-    }
     // Extend the converters for primitive types by NumPy ones.
     extendArrayConverter1<short, NPY_SHORT>();
     extendArrayConverter2<short, NPY_SHORT>();
index 225ed74e569a3ca95ffa4e555633dddb0d37d209..023de0ea49ee63a3a32973e43e51a1a78dcb175f 100644 (file)
@@ -24,6 +24,7 @@ STATIC_STRING_IMPL(im_self, "im_self")
 STATIC_STRING_IMPL(loads, "loads")
 STATIC_STRING_IMPL(multi, "multi")
 STATIC_STRING_IMPL(name, "name")
+STATIC_STRING_IMPL(orig_dict, "orig_dict")
 STATIC_STRING_IMPL(qApp, "qApp")
 STATIC_STRING_IMPL(result, "result")
 STATIC_STRING_IMPL(select_id, "select_id")
index 02cc8a7f6241ef273a6b4603fdbf22884d90e9b0..017790ee36c26700af3414d69820c69fd87c777a 100644 (file)
@@ -23,6 +23,7 @@ LIBSHIBOKEN_API PyObject *im_self();
 LIBSHIBOKEN_API PyObject *loads();
 LIBSHIBOKEN_API PyObject *multi();
 LIBSHIBOKEN_API PyObject *name();
+LIBSHIBOKEN_API PyObject *orig_dict();
 LIBSHIBOKEN_API PyObject *result();
 LIBSHIBOKEN_API PyObject *select_id();
 LIBSHIBOKEN_API PyObject *value();
index 4699f7c68b50b147256d831c159651a09e278953..079548eed1d764be6df6c580cdba696da2515d26 100644 (file)
@@ -77,7 +77,11 @@ static PyObject *_PyType_FromSpecWithBasesHack(PyType_Spec *spec,
         }
     }
 
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+    auto *ret = PyType_FromMetaclass(meta, nullptr /*module*/, spec, bases);
+#else
     auto *ret = _PyType_FromSpecWithBases(spec, bases);
+#endif
 
     if (keepMeta)
         keepMeta->tp_new = keepNew;
index 6c0ecbe3001c944a7dadf1b0a2d077529d3b1c1a..fcf777ae0e41a9c06cf7ee2de421812fd8de86aa 100644 (file)
@@ -11,6 +11,7 @@
 #include "gilstate.h"
 #include "threadstatesaver.h"
 #include "helper.h"
+#include "pyobjectholder.h"
 #include "sbkarrayconverter.h"
 #include "sbkconverter.h"
 #include "sbkenum.h"
index 814d0ceab44274363a99723ac599f1303b1c87d0..3255cb56d1cce8ed2ae93cc2b20f5ba622fa00eb 100644 (file)
@@ -248,6 +248,9 @@ PyObject *get_signature_intern(PyObject *ob, PyObject *modifier)
         return pyside_tp_get___signature__(ob, modifier);
     if (Py_TYPE(ob) == &PyWrapperDescr_Type)
         return pyside_wd_get___signature__(ob, modifier);
+    // For classmethods we use the simple wrapper description implementation.
+    if (Py_TYPE(ob) == &PyClassMethodDescr_Type)
+        return pyside_wd_get___signature__(ob, modifier);
     return nullptr;
 }
 
@@ -471,6 +474,8 @@ void FinishSignatureInitialization(PyObject *module, const char *signatures[])
      * Still, it is not possible to call init phase 2 from here,
      * because the import is still running. Do it from Python!
      */
+    init_shibokensupport_module();
+
 #ifndef PYPY_VERSION
     static const bool patch_types = true;
 #else
index ca560d00f8b1aa64dc28c4d013ae4d8b1b7c121e..7292f8216831987380052bd65e2c389f0423a0fb 100644 (file)
@@ -77,7 +77,7 @@ PyObject *pyside_md_get___signature__(PyObject *ob_md, PyObject *modifier)
 {
     AutoDecRef func(name_key_to_func(ob_md));
     if (func.object() == Py_None)
-        return Py_None;
+        Py_RETURN_NONE;
     if (func.isNull())
         Py_FatalError("missing mapping in MethodDescriptor");
     return pyside_cf_get___signature__(func, modifier);
index e9d88305d444c8ec3c34f3c8855a6a46116f061a..cf84cfa13e64069dda8b5fe1ddeeae488e496729 100644 (file)
@@ -312,6 +312,15 @@ int _build_func_to_type(PyObject *obtype)
     auto *type = reinterpret_cast<PyTypeObject *>(obtype);
     AutoDecRef tpDict(PepType_GetDict(type));
     auto *dict = tpDict.object();
+
+    // PYSIDE-2404: Get the original dict for late initialization.
+    //              The dict might have been switched before signature init.
+    static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type);
+    if (Py_TYPE(dict) != Py_TYPE(pyTypeType_tp_dict)) {
+        tpDict.reset(PyObject_GetAttr(dict, PyName::orig_dict()));
+        dict = tpDict.object();
+    }
+
     PyMethodDef *meth = type->tp_methods;
 
     if (meth == nullptr)
index ed4f88ad182e3845e67712831922017fb415ffd6..8bb3f6ac88b2a7a78bbb963d8b1db6f3c35bb377 100644 (file)
@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "voidptr.h"
+#include "pep384ext.h"
 #include "sbkconverter.h"
 #include "basewrapper.h"
 #include "basewrapper_p.h"
@@ -24,8 +25,7 @@ PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject * /* args */, PyObje
     // like this, actual call forgotten:
     //    SbkVoidPtrObject *self =
     //        reinterpret_cast<SbkVoidPtrObject *>(type->tp_alloc);
-    PyObject *ob = type->tp_alloc(type, 0);
-    auto *self = reinterpret_cast<SbkVoidPtrObject *>(ob);
+    auto *self = PepExt_TypeCallAlloc<SbkVoidPtrObject>(type, 0);
 
     if (self != nullptr) {
         self->cptr = nullptr;
@@ -156,10 +156,9 @@ PyObject *SbkVoidPtrObject_int(PyObject *v)
 PyObject *toBytes(PyObject *self, PyObject * /* args */)
 {
     auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(self);
-    if (sbkObject->size < 0) {
-        PyErr_SetString(PyExc_IndexError, "VoidPtr does not have a size set.");
-        return nullptr;
-    }
+    if (sbkObject->size < 0)
+        return PyErr_Format(PyExc_IndexError, "VoidPtr does not have a size set.");
+
     PyObject *bytes = PyBytes_FromStringAndSize(reinterpret_cast<const char *>(sbkObject->cptr),
                                                 sbkObject->size);
     Py_XINCREF(bytes);
index d403c7582f1b006ba35c78780f075d71a75e1fda..7a0871ee7d0c969451c0393c5ba50f158525969a 100644 (file)
@@ -1,6 +1,9 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
+# flake8: noqa F:821
+# flake8: noqa F:401
+
 """
 __feature__.py  (renamed to feature.py)
 
@@ -80,6 +83,7 @@ None to indicate that a normal import should be performed, and
 All these variables are transparently kept in module `builtins`.
 """
 
+
 def feature_import(name, *args, **kwargs):
     # PYSIDE-1368: The `__name__` attribute does not need to exist in all modules.
     # PYSIDE-1398: sys._getframe(1) may not exist when embedding.
@@ -110,8 +114,10 @@ def feature_import(name, *args, **kwargs):
     # Redirect to the original import
     return None
 
+
 _is_initialized = False
 
+
 def __init__():
     global _is_initialized
     if not _is_initialized:
@@ -182,6 +188,7 @@ def set_selection(select_id, mod_name=None):
     sys.modules["PySide6.QtCore"].__init_feature__()
     return _current_selection(flag)
 
+
 # The set_section(0) case seems to be unsafe. We will migrate to
 # use the opaque feature.reset() call in all test cases.
 def reset():
index 3e1d49328847405a56ff276efe7f08d89f838621..f7190b12f12a5eae67750597c1d70d55b1a184de 100644 (file)
@@ -9,7 +9,6 @@ Run it once after copying a new version. It is idem-potent, unless
 you are changing messages (what I did, of course :-) .
 """
 
-import os
 import glob
 from pathlib import Path
 
@@ -24,6 +23,7 @@ offending_words = {
 utf8_line = "# This Python file uses the following encoding: utf-8\n"
 marker_line = f"# It has been edited by {Path(__file__).name} .\n"
 
+
 def patch_file(fname):
     with fname.open() as f:
         lines = f.readlines()
@@ -41,6 +41,7 @@ def patch_file(fname):
         with open(fname, "w") as f:
             f.write("".join(lines))
 
+
 def doit():
     dirname = Path(__file__).parent
     patched_files = []
@@ -51,6 +52,7 @@ def doit():
         print("Working on", fname)
         patch_file(fname)
 
+
 if __name__ == "__main__":
     doit()
 
index 5b63de45af1b7d6c0dca215fa72f281dc4f023a1..c2a19efef3fb28093c7c2d21ba26d90aabf7ccb3 100644 (file)
@@ -1,6 +1,8 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
+# flake8: noqa E:721
+
 """
 errorhandler.py
 
@@ -19,12 +21,10 @@ This matter will be improved in a later version.
 """
 
 import collections.abc
-import inspect
-import sys
 import typing
 
 from shibokensupport.signature import get_signature
-from shibokensupport.signature.mapping import update_mapping, namespace
+from shibokensupport.signature.mapping import namespace
 from textwrap import dedent
 
 
@@ -77,8 +77,8 @@ def seterror_argument(args, func_name, info):
         if info == "<":
             msg = f"{func_name}(): not enough arguments"
         elif info == "0":
-           msg = (f"{func_name}(): not enough arguments. "
-                  "Note: keyword arguments are only supported for optional parameters.")
+            msg = (f"{func_name}(): not enough arguments. "
+                   "Note: keyword arguments are only supported for optional parameters.")
         elif info == ">":
             msg = f"{func_name}(): too many arguments"
         elif info.isalnum():
index dbde18f18d99d415d7fa6f815a0db89dd9dc0e6e..bae26429409d1fc618ada2a4deb4c3759be55649 100644 (file)
@@ -34,9 +34,10 @@ def finish_import(module):
         except Exception as e:
             name = e.__class__.__qualname__
             print(72 * "*")
-            print(f"Error in deprecated.py, ignored:")
+            print("Error in deprecated.py, ignored:")
             print(f"    {name}: {e}")
 
+
 """
 A note for people who might think this could be written in pure Python:
 
@@ -62,4 +63,3 @@ module, it is *perhaps* possible to solve that. I tried for a day and then
 gave up, since the solution is anyway not too nice when __import__ must
 be overridden.
 """
-#eof
index c271be7f7982f95ebdcb2b76212d8e630d00ba21..0e781cbcbf0ca0fbd3a235c04735105649527d0b 100644 (file)
@@ -79,6 +79,7 @@ class SignatureLayout(SimpleNamespace):
             The only allowed values are '{allowed_values}'.
             """))
 
+
 # The following names are used literally in this module.
 # This way, we avoid the dict hashing problem.
 signature = SignatureLayout()
@@ -115,7 +116,7 @@ def define_nameless_parameter():
     P = inspect.Parameter
     newname = "NamelessParameter"
     bases = P.__bases__
-    body = dict(P.__dict__) # get rid of mappingproxy
+    body = dict(P.__dict__)  # get rid of mappingproxy
     if "__slots__" in body:
         # __slots__ would create duplicates
         for name in body["__slots__"]:
@@ -167,12 +168,13 @@ def make_signature_nameless(signature):
         signature.parameters[key].__class__ = NamelessParameter
 
 
-_POSITIONAL_ONLY         = inspect._POSITIONAL_ONLY
-_POSITIONAL_OR_KEYWORD   = inspect._POSITIONAL_OR_KEYWORD
-_VAR_POSITIONAL          = inspect._VAR_POSITIONAL
-_KEYWORD_ONLY            = inspect._KEYWORD_ONLY
-_VAR_KEYWORD             = inspect._VAR_KEYWORD
-_empty                   = inspect._empty
+_POSITIONAL_ONLY         = inspect._POSITIONAL_ONLY  # noqa E:201
+_POSITIONAL_OR_KEYWORD   = inspect._POSITIONAL_OR_KEYWORD  # noqa E:201
+_VAR_POSITIONAL          = inspect._VAR_POSITIONAL  # noqa E:201
+_KEYWORD_ONLY            = inspect._KEYWORD_ONLY  # noqa E:201
+_VAR_KEYWORD             = inspect._VAR_KEYWORD  # noqa E:201
+_empty                   = inspect._empty  # noqa E:201
+
 
 def create_signature(props, key):
     if not props:
@@ -183,9 +185,9 @@ def create_signature(props, key):
         return list(create_signature(elem, key)
                     for elem in props["multi"])
     if type(key) is tuple:
-        sig_kind, modifier = key
+        _, modifier = key
     else:
-        sig_kind, modifier = key, "signature"
+        _, modifier = key, "signature"
 
     layout = globals()[modifier]  # lookup of the modifier in this module
     if not isinstance(layout, SignatureLayout):
@@ -234,8 +236,8 @@ def create_signature(props, key):
         if kind == _VAR_POSITIONAL:
             kind = _KEYWORD_ONLY
     sig = inspect.Signature(params,
-           return_annotation=annotations.get('return', _empty),
-           __validate_parameters__=False)
+                            return_annotation=annotations.get('return', _empty),
+                            __validate_parameters__=False)
 
     # the special case of nameless parameters
     if not layout.parameter_names:
index d07beb88103c43075ed607ea41ffe7a3e61e4646..5650e2bc148d709fa0e59dde3d4ee81c16fc767f 100644 (file)
@@ -14,9 +14,7 @@ by producing a lot of clarity.
 import inspect
 import sys
 import types
-import typing
 from shibokensupport.signature import get_signature as get_sig
-from shibokensupport.signature.layout import create_signature
 
 
 """
@@ -106,7 +104,7 @@ class ExactEnumerator(object):
             return ret
         if "<" in class_name:
             # This is happening in QtQuick for some reason:
-            ## class std::shared_ptr<QQuickItemGrabResult >:
+            # class std::shared_ptr<QQuickItemGrabResult >:
             # We simply skip over this class.
             return ret
         bases_list = []
@@ -125,6 +123,7 @@ class ExactEnumerator(object):
         enums = []
         properties = []
         signals = []
+        attributes = {}
 
         for thing_name, thing in class_members:
             if signal_check(thing):
@@ -147,6 +146,13 @@ class ExactEnumerator(object):
                     enums.append((thing_name, type(thing).__qualname__, thing))
             elif isinstance(thing, property):
                 properties.append((thing_name, thing))
+            # Support attributes that have PySide types as values,
+            # but we skip the 'staticMetaObject' that needs
+            # to be defined at a QObject level.
+            elif "PySide" in str(type(thing)) and "QMetaObject" not in str(type(thing)):
+                if class_name not in attributes:
+                    attributes[class_name] = {}
+                attributes[class_name][thing_name] = thing
 
             if thing_name in self.collision_candidates:
                 self.collision_track.add(thing_name)
@@ -160,8 +166,8 @@ class ExactEnumerator(object):
 
         # find out how many functions create a signature
         sigs = list(_ for _ in functions if get_sig(_[1]))
-        self.fmt.have_body = bool(subclasses or sigs or properties or enums or init_signature
-                                  or signals)
+        self.fmt.have_body = bool(subclasses or sigs or properties or enums or  # noqa W:504
+                                  init_signature or signals or attributes)
 
         with self.fmt.klass(class_name, class_str):
             self.fmt.level += 1
@@ -171,7 +177,7 @@ class ExactEnumerator(object):
                 if len(enums):
                     self.section()
                 for enum_name, enum_class_name, value in enums:
-                    with self.fmt.enum(enum_class_name, enum_name,value.value):
+                    with self.fmt.enum(enum_class_name, enum_name, value.value):
                         pass
             if hasattr(self.fmt, "signal"):
                 # this is an optional feature
@@ -183,6 +189,13 @@ class ExactEnumerator(object):
                     sig_str = str(signal)
                     with self.fmt.signal(sig_class_name, signal_name, sig_str):
                         pass
+            if hasattr(self.fmt, "attribute"):
+                if len(attributes):
+                    self.section()
+                for class_name, attrs in attributes.items():
+                    for attr_name, attr_value in attrs.items():
+                        with self.fmt.attribute(attr_name, attr_value):
+                            pass
             if len(subclasses):
                 self.section()
             for subclass_name, subclass in subclasses:
index c44346687151edd8d702f523e63523035d63903e..ce12dd6c8d1331f6905c0ec0e652b2beb449bcd0 100644 (file)
@@ -3,6 +3,8 @@ LICENSE_TEXT = """
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 """
 
+# flake8: noqa E:402
+
 """
 pyi_generator.py
 
@@ -21,7 +23,6 @@ from pathlib import Path
 from contextlib import contextmanager
 from textwrap import dedent
 
-from shiboken6 import Shiboken
 from shibokensupport.signature.lib.enum_sig import HintingEnumerator
 from shibokensupport.signature.lib.tool import build_brace_pattern
 
@@ -89,6 +90,7 @@ class Formatter(Writer):
         pattern = fr"\b Union \s* \[ \s* {brace_pat} \s*, \s* NoneType \s* \]"
         replace = r"Optional[\1]"
         optional_searcher = re.compile(pattern, flags=re.VERBOSE)
+
         def optional_replacer(source):
             return optional_searcher.sub(replace, str(source))
         self.optional_replacer = optional_replacer
@@ -156,6 +158,12 @@ class Formatter(Writer):
         self.print(f"{spaces}{enum_name:25}: {class_name} = ... # {hexval}")
         yield
 
+    @contextmanager
+    def attribute(self, attr_name, attr_value):
+        spaces = indent * self.level
+        self.print(f"{spaces}{attr_name:25} = ...  # type: {type(attr_value).__qualname__}")
+        yield
+
     @contextmanager
     def signal(self, class_name, sig_name, sig_str):
         spaces = indent * self.level
@@ -171,11 +179,13 @@ FROM_IMPORTS = [
     (None, ["builtins"]),
     (None, ["os"]),
     (None, ["enum"]),
+    ("collections.abc", ["Iterable"]),
     ("typing", sorted(typing.__all__)),
     ("PySide6.QtCore", ["PyClassProperty", "Signal", "SignalInstance"]),
     ("shiboken6", ["Shiboken"]),
     ]
 
+
 def filter_from_imports(from_struct, text):
     """
     Build a reduced new `from` structure (nfs) with found entries, only
@@ -190,6 +200,10 @@ def filter_from_imports(from_struct, text):
             if (f"class {each}(") not in text:
                 if re.search(rf"(\b|@){each}\b([^\s\(:]|\n)", text):
                     lis.append(each)
+                # Search if a type is present in the return statement
+                # of function declarations: '... -> here:'
+                if re.search(rf"->.*{each}.*:", text):
+                    lis.append(each)
         if not lis:
             nfs.pop()
     return nfs
@@ -228,12 +242,10 @@ def generate_pyi(import_name, outpath, options):
     obj = getattr(top, plainname) if import_name != plainname else top
     if not getattr(obj, "__file__", None) or Path(obj.__file__).is_dir():
         raise ModuleNotFoundError(f"We do not accept a namespace as module `{plainname}`")
-    module = sys.modules[import_name]
 
     outfile = io.StringIO()
     fmt = Formatter(outfile, options)
     fmt.print(LICENSE_TEXT.strip())
-    need_imports = options._pyside_call and not USE_PEP563
     if USE_PEP563:
         fmt.print("from __future__ import annotations")
         fmt.print()
@@ -275,15 +287,12 @@ def generate_pyi(import_name, outpath, options):
                         wr.print(f"from {mod} import {import_args}")
                 wr.print()
                 wr.print()
-                wr.print("NoneType = type(None)")
+                wr.print("NoneType: TypeAlias = type[None]")
                 wr.print()
             else:
                 wr.print(line)
     if not options.quiet:
         options.logger.info(f"Generated: {outfilepath}")
-    # PYSIDE-1735: .pyi files are no longer compatible with Python, because
-    #              enum classes contain ellipsis which a Python enum forbids.
-    #              We will implement tests with Mypy, instead.
 
 
 def main():
@@ -298,11 +307,10 @@ def main():
             pyi_generator will try to generate an interface "<module>.pyi".
             """))
     parser.add_argument("module",
-        help="The full path name of an importable module binary (.pyd, .so)")
+        help="The full path name of an importable module binary (.pyd, .so)")  # noqa E:128
     parser.add_argument("--quiet", action="store_true", help="Run quietly")
-    parser.add_argument("--check", action="store_true", help="Test the output")
     parser.add_argument("--outpath",
-        help="the output directory (default = location of module binary)")
+        help="the output directory (default = location of module binary)")  # noqa E:128
     options = parser.parse_args()
     module = options.module
     outpath = options.outpath
@@ -320,6 +328,7 @@ def main():
     options.logger = logger
     generate_pyi(module, outpath, options=options)
 
+
 if __name__ == "__main__":
     main()
 # eof
index a7900e6b289954032c900dfc2dc04ee92fb0dba0..979dcf4ce76ce8cf87070d4e651cd64bfcc4d6af 100644 (file)
@@ -44,8 +44,8 @@ def build_brace_pattern(level, separators):
 
     ro, rc = round_ = "()"
     so, sc = square = "[]"
-    co, cc = curly  = "CD"      # we insert "{}", later...
-    ao, ac = angle  = "<>"
+    co, cc = curly  = "CD"  # noqa E:201 we insert "{}", later...
+    ao, ac = angle  = "<>"  # noqa E:201
     q2, bs, q1 = '"', "\\", "'"
     allpat = round_ + square + curly + angle
     __ = "  "
@@ -79,8 +79,8 @@ def build_brace_pattern(level, separators):
         {indent}  )*
         """)
     for idx in range(level):
-        pattern = pattern.format(replacer = repeated if idx < level-1 else no_braces_q,
-                                 indent = idx * "    ", **locals())
+        pattern = pattern.format(replacer=repeated if idx < level - 1 else no_braces_q,
+                                 indent=idx * "    ", **locals())
     return pattern.replace("C", "{").replace("D", "}")
 
 
index 6349253d1f0cebdef4dcdc2dbe87e61be704ea55..fb4c9eecac9bf744a93762946985191bfec62349 100644 (file)
@@ -1,6 +1,9 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
+# flake8: noqa E:402
+# flake8: noqa F:401
+
 """
 loader.py
 
@@ -30,22 +33,27 @@ import types
 def pyside_type_init(type_key, sig_strings):
     return parser.pyside_type_init(type_key, sig_strings)
 
+
 # name used in signature.cpp
 def create_signature(props, key):
     return layout.create_signature(props, key)
 
+
 # name used in signature.cpp
 def seterror_argument(args, func_name, info):
     return errorhandler.seterror_argument(args, func_name, info)
 
+
 # name used in signature.cpp
 def make_helptext(func):
     return errorhandler.make_helptext(func)
 
+
 # name used in signature.cpp
 def finish_import(module):
     return importhandler.finish_import(module)
 
+
 # name used in signature.cpp
 def feature_import(*args, **kwds):
     # don't spend a stack level here for speed and compatibility
@@ -53,6 +61,7 @@ def feature_import(*args, **kwds):
     feature_import = feature.feature_import
     return feature_import(*args, **kwds)
 
+
 # name used in signature.cpp
 def feature_imported(*args, **kwds):
     # don't spend a stack level here for speed and compatibility
@@ -107,6 +116,7 @@ def move_into_pyside_package():
     put_into_package(PySide6.support.signature.lib, pyi_generator)
     put_into_package(PySide6.support.signature.lib, tool)
 
+
 from shibokensupport.signature import mapping
 from shibokensupport.signature import errorhandler
 from shibokensupport.signature import layout
@@ -119,7 +129,7 @@ from shibokensupport.signature.lib import tool
 
 import enum
 
-post_init = lambda:None     # default
+post_init = lambda: None  # noqa E:731 default
 
 if "PySide6" in sys.modules:
     # We publish everything under "PySide6.support", again.
@@ -127,7 +137,7 @@ if "PySide6" in sys.modules:
     # PYSIDE-1502: Make sure that support can be imported.
     try:
         import PySide6.support
-    except ModuleNotFoundError as e:
+    except ModuleNotFoundError:
         print("PySide6.support could not be imported. "
               "This is a serious configuration error.", file=sys.stderr)
         raise
index 1af82e316b4ddbd3e99a1eb62845d4a4cea6e0d5..944a928e688ad5b8316b6f2e610dbd492fc8e6b1 100644 (file)
@@ -212,9 +212,9 @@ type_map.update({
     "PyCallable": typing.Callable,
     "PyObject": object,
     "PyObject*": object,
-    "PyArrayObject": ArrayLikeVariable,  # numpy
-    "PyPathLike": typing.Union[str, bytes, os.PathLike],
-    "PySequence": typing.Iterable,   # important for numpy
+    "PyArrayObject": ArrayLikeVariable, # numpy
+    "PyPathLike": typing.Union[str, bytes, os.PathLike[str]],
+    "PySequence": typing.Iterable,  # important for numpy
     "PyTypeObject": type,
     "QChar": str,
     "QHash": typing.Dict,
@@ -241,6 +241,7 @@ type_map.update({
     "qreal": float,
     "QSet": typing.Set,
     "QString": str,
+    "QLatin1String": str,
     "QStringView": str,
     "QStringList": StringList,
     "quint16": int,
@@ -522,6 +523,7 @@ def init_PySide6_QtCore():
         "QVariant()": Invalid(Variant),
         "QVariant.Type": type,  # not so sure here...
         "QVariantMap": typing.Dict[str, Variant],
+        "std.chrono.seconds{5}" : ellipsis,
     })
     try:
         type_map.update({
@@ -559,6 +561,7 @@ def init_PySide6_QtGui():
         "int32_t": int,
         "HBITMAP": int,
         "HICON": int,
+        "HMONITOR": int,
         "HRGN": int,
         "QPixmap()": Default("PySide6.QtGui.QPixmap"),  # can't create without qApp
         "QPlatformSurface*": int,  # a handle
index 1936215dda29dc2af4ff1981630d3353ee89703f..9b48ab44291f2f489c5d2a1ad0404271826c3f9b 100644 (file)
@@ -3,20 +3,17 @@
 
 import ast
 import enum
-import functools
 import keyword
 import os
 import re
 import sys
-import types
 import typing
 import warnings
 
 from types import SimpleNamespace
 from shibokensupport.signature.mapping import (type_map, update_mapping,
-    namespace, _NotCalled, ResultVariable, ArrayLikeVariable)
+    namespace, _NotCalled, ResultVariable, ArrayLikeVariable)  # noqa E:128
 from shibokensupport.signature.lib.tool import build_brace_pattern
-from shibokensupport import feature
 
 _DEBUG = False
 LIST_KEYWORDS = False
@@ -41,8 +38,9 @@ guesses, we provide an entry in 'type_map' that resolves it.
 In effect, 'type_map' maps text to real Python objects.
 """
 
+
 def _get_flag_enum_option():
-    from shiboken6 import (__version_info__ as ver,
+    from shiboken6 import (__version_info__ as ver,  # noqa F:401
                            __minimum_python_version__ as pyminver,
                            __maximum_python_version__ as pymaxver)
 
@@ -80,6 +78,9 @@ def _get_flag_enum_option():
     # PYSIDE-1735: Emit a warning when we should maybe evict forgiveness mode
     if ver[:2] >= (7, 0):
         warnings.warn(f"{q} Please drop Enum forgiveness mode in `mangled_type_getattro` ***")
+    # PYSIDE-2404: Emit a warning when we should drop uppercase offset constants
+    if ver[:2] >= (7, 0):
+        warnings.warn(f"{q} Please drop uppercase type offsets in `copyOffsetEnumStream` ***")
     # normalize the sys attribute
     setattr(sys, sysname, flag)
     os.environ[envname] = str(flag)
@@ -106,6 +107,7 @@ def dprint(*args, **kw):
 
 _cache = {}
 
+
 def _parse_arglist(argstr):
     # The following is a split re. The string is broken into pieces which are
     # between the recognized strings. Because the re has groups, both the
@@ -187,7 +189,7 @@ def _handle_instance_fixup(thing):
     if not match:
         return thing
     start, stop = match.start(), match.end() - 1
-    pre, func, args = thing[:start], thing[start : stop], thing[stop:]
+    pre, func, args = thing[:start], thing[start:stop], thing[stop:]
     if func[0].isupper() or func.startswith("gl") and func[2:3].isupper():
         return thing
     # Now convert this string to snake case.
@@ -196,7 +198,7 @@ def _handle_instance_fixup(thing):
         if char.isupper():
             if idx and func[idx - 1].isupper():
                 # two upper chars are forbidden
-                return things
+                return thing
             snake_func += f"_{char.lower()}"
         else:
             snake_func += char
@@ -239,12 +241,14 @@ def try_to_guess(thing, valtype):
                 return ret
     return None
 
+
 def get_name(thing):
     if isinstance(thing, type):
         return getattr(thing, "__qualname__", thing.__name__)
     else:
         return thing.__name__
 
+
 def _resolve_value(thing, valtype, line):
     if thing in ("0", "None") and valtype:
         if valtype.startswith("PySide6.") or valtype.startswith("typing."):
@@ -297,7 +301,7 @@ def to_string(thing):
         dot = "." in str(thing) or m not in (thing.__qualname__, "builtins")
         name = get_name(thing)
         ret = m + "." + name if dot else name
-        assert(eval(ret, globals(), namespace))
+        assert (eval(ret, globals(), namespace))
         return ret
     # Note: This captures things from the typing module:
     return str(thing)
@@ -305,8 +309,9 @@ def to_string(thing):
 
 matrix_pattern = "PySide6.QtGui.QGenericMatrix"
 
+
 def handle_matrix(arg):
-    n, m, typstr = tuple(map(lambda x:x.strip(), arg.split(",")))
+    n, m, typstr = tuple(map(lambda x: x.strip(), arg.split(",")))
     assert typstr == "float"
     result = f"PySide6.QtGui.QMatrix{n}x{m}"
     return eval(result, globals(), namespace)
@@ -334,13 +339,13 @@ def _resolve_type(thing, line, level, var_handler, func_name=None):
         # Special case: Handle the generic matrices.
         if contr == matrix_pattern:
             return handle_matrix(thing)
-        contr = var_handler(_resolve_type(contr, line, level+1, var_handler))
+        contr = var_handler(_resolve_type(contr, line, level + 1, var_handler))
         if isinstance(contr, _NotCalled):
             raise SystemError("Container types must exist:", repr(contr))
         contr = to_string(contr)
         pieces = []
         for part in _parse_arglist(thing):
-            part = var_handler(_resolve_type(part, line, level+1, var_handler))
+            part = var_handler(_resolve_type(part, line, level + 1, var_handler))
             if isinstance(part, _NotCalled):
                 # fix the tag (i.e. "Missing") by repr
                 part = repr(part)
@@ -350,7 +355,7 @@ def _resolve_type(thing, line, level, var_handler, func_name=None):
         # PYSIDE-1538: Make sure that the eval does not crash.
         try:
             return eval(result, globals(), namespace)
-        except Exception as e:
+        except Exception:
             warnings.warn(f"""pyside_type_init:_resolve_type
 
                 UNRECOGNIZED:   {result!r}
@@ -429,9 +434,9 @@ def calculate_props(line):
     props.defaults = defaults
     props.kwdefaults = {}
     props.annotations = annotations
-    props.varnames = varnames = tuple(tup[0] for tup in arglist)
+    props.varnames = tuple(tup[0] for tup in arglist)
     funcname = parsed.funcname
-    shortname = funcname[funcname.rindex(".")+1:]
+    shortname = funcname[funcname.rindex(".") + 1:]
     props.name = shortname
     props.multi = parsed.multi
     fix_variables(props, line)
@@ -477,7 +482,6 @@ def fix_variables(props, line):
         else:
             diff -= 1
     if retvars:
-        rvs = []
         retvars = list(handle_retvar(rv) if isinstance(rv, ArrayLikeVariable) else rv
                        for rv in retvars)
         if len(retvars) == 1:
diff --git a/sources/shiboken6/shibokenmodule/shibokenmodule.cpp b/sources/shiboken6/shibokenmodule/shibokenmodule.cpp
new file mode 100644 (file)
index 0000000..b3adfe7
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// @snippet isvalid
+bool isValid = Shiboken::Object::isValid(%1, false);
+%PYARG_0 = %CONVERTTOPYTHON[bool](isValid);
+// @snippet isvalid
+
+// @snippet wrapinstance
+auto *pyType = reinterpret_cast<PyTypeObject *>(%2);
+if (Shiboken::ObjectType::checkType(pyType)) {
+    auto *ptr = reinterpret_cast<void *>(%1);
+    if (auto *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(ptr)) {
+        Py_INCREF(wrapper);
+        %PYARG_0 = reinterpret_cast<PyObject *>(wrapper);
+    } else {
+        %PYARG_0 = Shiboken::Object::newObject(pyType, ptr, false, true);
+    }
+} else {
+    PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
+}
+// @snippet wrapinstance
+
+// @snippet getcpppointer
+if (Shiboken::Object::checkType(%1)) {
+    std::vector<void*> ptrs = Shiboken::Object::cppPointers(reinterpret_cast<SbkObject *>(%1));
+    %PYARG_0 = PyTuple_New(ptrs.size());
+    for (std::size_t i = 0; i < ptrs.size(); ++i)
+        PyTuple_SET_ITEM(%PYARG_0, i, PyLong_FromVoidPtr(ptrs[i]));
+} else {
+    PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
+}
+// @snippet getcpppointer
+
+// @snippet delete
+if (Shiboken::Object::checkType(%1)) {
+    Shiboken::Object::callCppDestructors(reinterpret_cast<SbkObject *>(%1));
+} else {
+    PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
+}
+// @snippet delete
+
+// @snippet ownedbypython
+if (Shiboken::Object::checkType(%1)) {
+    bool hasOwnership = Shiboken::Object::hasOwnership(reinterpret_cast<SbkObject *>(%1));
+    %PYARG_0 = %CONVERTTOPYTHON[bool](hasOwnership);
+} else {
+    PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
+}
+// @snippet ownedbypython
+
+// @snippet createdbypython
+if (Shiboken::Object::checkType(%1)) {
+    bool wasCreatedByPython = Shiboken::Object::wasCreatedByPython(reinterpret_cast<SbkObject *>(%1));
+    %PYARG_0 = %CONVERTTOPYTHON[bool](wasCreatedByPython);
+} else {
+    PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
+}
+// @snippet createdbypython
+
+// @snippet disassembleframe
+Shiboken::AutoDecRef label(PyObject_Str(%1));
+const char *marker = Shiboken::String::toCString(label);
+disassembleFrame(marker);
+Py_INCREF(Py_None);
+%PYARG_0 = Py_None;
+// @snippet disassembleframe
+
+// @snippet dump
+if (!Shiboken::Object::checkType(%1)) {
+    %PYARG_0 = Shiboken::String::fromCString("Ordinary Python type.");
+} else {
+    std::string str = Shiboken::Object::info(reinterpret_cast<SbkObject *>(%1));
+    %PYARG_0 = Shiboken::String::fromCString(str.c_str());
+}
+// @snippet dump
+
+// @snippet getallvalidwrappers
+const auto setAll = Shiboken::BindingManager::instance().getAllPyObjects();
+PyObject* listAll = PyList_New(0);
+if (listAll == nullptr)
+    return nullptr;
+for (auto *o : setAll) {
+    if (o != nullptr) {
+        if (PyList_Append(listAll, o) != 0) {
+            Py_DECREF(listAll);
+            return nullptr;
+        }
+    }
+}
+return listAll;
+// @snippet getallvalidwrappers
+
+// @snippet dumptypegraph
+const bool ok = Shiboken::BindingManager::instance().dumpTypeGraph(%1);
+%PYARG_0 = %CONVERTTOPYTHON[bool](ok);
+// @snippet dumptypegraph
+
+// @snippet dumpwrappermap
+Shiboken::BindingManager::instance().dumpWrapperMap();
+// @snippet dumpwrappermap
+
+// @snippet init
+// Add __version__ and __version_info__ attributes to the module
+PyObject* version = PyTuple_New(5);
+PyTuple_SET_ITEM(version, 0, PyLong_FromLong(SHIBOKEN_MAJOR_VERSION));
+PyTuple_SET_ITEM(version, 1, PyLong_FromLong(SHIBOKEN_MINOR_VERSION));
+PyTuple_SET_ITEM(version, 2, PyLong_FromLong(SHIBOKEN_MICRO_VERSION));
+PyTuple_SET_ITEM(version, 3, Shiboken::String::fromCString(SHIBOKEN_RELEASE_LEVEL));
+PyTuple_SET_ITEM(version, 4, PyLong_FromLong(SHIBOKEN_SERIAL));
+PyModule_AddObject(module, "__version_info__", version);
+PyModule_AddStringConstant(module, "__version__", SHIBOKEN_VERSION);
+VoidPtr::addVoidPtrToModule(module);
+Shiboken::initShibokenSupport(module);
+// @snippet init
index de5003d5b40b6d57dcc67e24a9bf3f7a4993938d..aa08a8bbfbf92ff812d01492c7cb7bcc109dce94 100644 (file)
@@ -1,13 +1,14 @@
 <?xml version="1.0" ?>
+<!--
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+-->
 <typesystem package="Shiboken">
     <primitive-type name="bool" />
     <primitive-type name="unsigned long" />
     <primitive-type name="size_t" />
     <add-function signature="isValid(PyObject*)" return-type="bool">
-        <inject-code>
-            bool isValid = Shiboken::Object::isValid(%1, false);
-            %PYARG_0 = %CONVERTTOPYTHON[bool](isValid);
-        </inject-code>
+        <inject-code file="shibokenmodule.cpp" snippet="isvalid"/>
     </add-function>
 
     <add-function signature="invalidate(PyObject*)">
     </add-function>
 
     <add-function signature="wrapInstance(size_t, PyTypeObject)" return-type="PyObject*">
-        <inject-code>
-            auto *pyType = reinterpret_cast&lt;PyTypeObject *&gt;(%2);
-            if (Shiboken::ObjectType::checkType(pyType)) {
-                %PYARG_0 = Shiboken::Object::newObject(pyType,
-                                                       reinterpret_cast&lt;void *&gt;(%1),
-                                                       false, true);
-            } else {
-                PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
-            }
-        </inject-code>
+        <inject-code file="shibokenmodule.cpp" snippet="wrapinstance"/>
     </add-function>
 
    <add-function signature="getCppPointer(PyObject*)" return-type="PySequence*">
-        <inject-code>
-            if (Shiboken::Object::checkType(%1)) {
-                std::vector&lt;void*> ptrs = Shiboken::Object::cppPointers(reinterpret_cast&lt;SbkObject *&gt;(%1));
-                %PYARG_0 = PyTuple_New(ptrs.size());
-                for (std::size_t i = 0; i &lt; ptrs.size(); ++i)
-                    PyTuple_SET_ITEM(%PYARG_0, i, PyLong_FromVoidPtr(ptrs[i]));
-            } else {
-                PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
-            }
-        </inject-code>
+        <inject-code file="shibokenmodule.cpp" snippet="getcpppointer"/>
    </add-function>
 
    <add-function signature="delete(PyObject*)">
-        <inject-code>
-            if (Shiboken::Object::checkType(%1)) {
-                Shiboken::Object::callCppDestructors(reinterpret_cast&lt;SbkObject *&gt;(%1));
-            } else {
-                PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
-            }
-        </inject-code>
+        <inject-code file="shibokenmodule.cpp" snippet="delete"/>
    </add-function>
 
     <add-function signature="ownedByPython(PyObject*)" return-type="bool">
-        <inject-code>
-            if (Shiboken::Object::checkType(%1)) {
-                bool hasOwnership = Shiboken::Object::hasOwnership(reinterpret_cast&lt;SbkObject *&gt;(%1));
-                %PYARG_0 = %CONVERTTOPYTHON[bool](hasOwnership);
-            } else {
-                PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
-            }
-        </inject-code>
+        <inject-code file="shibokenmodule.cpp" snippet="ownedbypython"/>
     </add-function>
 
     <add-function signature="createdByPython(PyObject*)" return-type="bool">
-        <inject-code>
-            if (Shiboken::Object::checkType(%1)) {
-                bool wasCreatedByPython = Shiboken::Object::wasCreatedByPython(reinterpret_cast&lt;SbkObject *&gt;(%1));
-                %PYARG_0 = %CONVERTTOPYTHON[bool](wasCreatedByPython);
-            } else {
-                PyErr_SetString(PyExc_TypeError, "You need a shiboken-based type.");
-            }
-        </inject-code>
+        <inject-code file="shibokenmodule.cpp" snippet="createdbypython"/>
     </add-function>
 
     <add-function signature="disassembleFrame(PyObject*)" return-type="PyObject">
-        <inject-code>
-            Shiboken::AutoDecRef label(PyObject_Str(%1));
-            const char *marker = Shiboken::String::toCString(label);
-            disassembleFrame(marker);
-            Py_INCREF(Py_None);
-            %PYARG_0 = Py_None;
-        </inject-code>
+        <inject-code file="shibokenmodule.cpp" snippet="disassembleframe"/>
     </add-function>
 
     <add-function signature="dump(PyObject*)" return-type="const char *">
-        <inject-code>
-            if (!Shiboken::Object::checkType(%1)) {
-                %PYARG_0 = Shiboken::String::fromCString("Ordinary Python type.");
-            } else {
-                std::string str = Shiboken::Object::info(reinterpret_cast&lt;SbkObject *&gt;(%1));
-                %PYARG_0 = Shiboken::String::fromCString(str.c_str());
-            }
-        </inject-code>
+        <inject-code file="shibokenmodule.cpp" snippet="dump"/>
     </add-function>
 
     <add-function signature="getAllValidWrappers(void)" return-type="PySequence*">
-        <inject-code>
-            const auto setAll = Shiboken::BindingManager::instance().getAllPyObjects();
-            PyObject* listAll = PyList_New(0);
-            if (listAll == nullptr)
-                return nullptr;
+        <inject-code file="shibokenmodule.cpp" snippet="getallvalidwrappers"/>
+    </add-function>
 
-            for (auto *o : setAll) {
-                if (o != nullptr) {
-                    if (PyList_Append(listAll, o) != 0) {
-                        Py_DECREF(listAll);
-                        return nullptr;
-                    }
-                }
-            }
-            return listAll;
-        </inject-code>
+    <add-function signature="dumpTypeGraph(const char *@fileName@)" return-type="bool">
+        <inject-code file="shibokenmodule.cpp" snippet="dumptypegraph"/>
+    </add-function>
+
+    <add-function signature="dumpWrapperMap()">
+        <inject-code file="shibokenmodule.cpp" snippet="dumpwrappermap"/>
     </add-function>
 
     <extra-includes>
         <include file-name="sbkversion.h" location="local"/>
         <include file-name="voidptr.h" location="local"/>
     </extra-includes>
-    <inject-code position="end">
-        // Add __version__ and __version_info__ attributes to the module
-        PyObject* version = PyTuple_New(5);
-        PyTuple_SET_ITEM(version, 0, PyLong_FromLong(SHIBOKEN_MAJOR_VERSION));
-        PyTuple_SET_ITEM(version, 1, PyLong_FromLong(SHIBOKEN_MINOR_VERSION));
-        PyTuple_SET_ITEM(version, 2, PyLong_FromLong(SHIBOKEN_MICRO_VERSION));
-        PyTuple_SET_ITEM(version, 3, Shiboken::String::fromCString(SHIBOKEN_RELEASE_LEVEL));
-        PyTuple_SET_ITEM(version, 4, PyLong_FromLong(SHIBOKEN_SERIAL));
-        PyModule_AddObject(module, "__version_info__", version);
-        PyModule_AddStringConstant(module, "__version__", SHIBOKEN_VERSION);
-        VoidPtr::addVoidPtrToModule(module);
-
-        Shiboken::initShibokenSupport(module);
-    </inject-code>
+     <inject-code position="end" file="shibokenmodule.cpp" snippet="init"/>
 </typesystem>
index f69d67e46445ec664d20a6e6cd66fe0a962c479b..eb876634ca5def59c2c56b02d8f580752d23d821 100644 (file)
@@ -48,14 +48,14 @@ static const char *primitiveTypes[] = {
     "float", "double"
 };
 
-static inline QString nameAttribute() { return QStringLiteral("name"); }
+constexpr auto nameAttribute = "name"_L1;
 
 static void formatXmlClass(QXmlStreamWriter &writer, const ClassModelItem &klass);
 
 static void formatXmlEnum(QXmlStreamWriter &writer, const EnumModelItem &en)
 {
     writer.writeStartElement(u"enum-type"_s);
-    writer.writeAttribute(nameAttribute(), en->name());
+    writer.writeAttribute(nameAttribute, en->name());
     writer.writeEndElement();
 }
 
@@ -97,7 +97,7 @@ static void formatXmlClass(QXmlStreamWriter &writer, const ClassModelItem &klass
     formatXmlLocationComment(writer, klass);
     writer.writeStartElement(isValueType ? u"value-type"_s
                                          : u"object-type"_s);
-    writer.writeAttribute(nameAttribute(), klass->name());
+    writer.writeAttribute(nameAttribute, klass->name());
     formatXmlScopeMembers(writer, klass);
     writer.writeEndElement();
 }
@@ -118,7 +118,7 @@ static void startXmlNamespace(QXmlStreamWriter &writer, const NamespaceModelItem
 {
     formatXmlLocationComment(writer, nsp);
     writer.writeStartElement(u"namespace-type"_s);
-    writer.writeAttribute(nameAttribute(), nsp->name());
+    writer.writeAttribute(nameAttribute, nsp->name());
 }
 
 static void formatXmlNamespaceMembers(QXmlStreamWriter &writer, const NamespaceModelItem &nsp)
@@ -170,7 +170,7 @@ static void formatXmlOutput(const FileModelItem &dom)
                         QDateTime::currentDateTime().toString(Qt::ISODate));
     for (auto p : primitiveTypes) {
         writer.writeStartElement(u"primitive-type"_s);
-        writer.writeAttribute(nameAttribute(), QLatin1StringView(p));
+        writer.writeAttribute(nameAttribute, QLatin1StringView(p));
         writer.writeEndElement();
     }
     formatXmlNamespaceMembers(writer, dom);
index a8e265388d1dee414820614398c670775ed5e78e..6165a6813418a89448c0282e56b4ba060043194d 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "libothermacros.h"
 #include "multiple_derived.h"
+#include "objecttype.h"
 #include "virtualmethods.h"
 
 class ObjectType;
index 648cedcd0b51920aa97ea2f3ae4d29d157a4de5a..0d67d86301371547f1b12627222d583628a62c5f 100644 (file)
@@ -49,6 +49,18 @@ void Abstract::show(PrintFormat format) const
     std::cout << '>';
 }
 
+void Abstract::virtualWithOutParameter(int &x) const
+{
+    x = 42;
+}
+
+int Abstract::callVirtualWithOutParameter() const
+{
+    int x;
+    virtualWithOutParameter(x);
+    return x;
+}
+
 void Abstract::callVirtualGettingEnum(PrintFormat p)
 {
     virtualGettingAEnum(p);
index 1e62a9c51c4979f8ff8af77de55d38fc09121498..4c1b98d90ea59e01b96d8831bebe35dfe844c3c8 100644 (file)
@@ -74,6 +74,9 @@ public:
 
     virtual void hideFunction(HideType *arg) = 0;
 
+    virtual void virtualWithOutParameter(int &x) const;
+    int callVirtualWithOutParameter() const;
+
 protected:
     virtual const char *className() const { return "Abstract"; }
 
index b7736c37aa19778028b6f1cc21599b406366fc06..cf95cb601eae40cadcdf2e5eb1f7013d0e2b3f2d 100644 (file)
@@ -26,7 +26,7 @@ public:
     public:
         void uselessMethod() {}
         SomeInnerClass operator+(const SomeInnerClass &other) { return other; }
-        bool operator==(const SomeInnerClass &) { return true; }
+        bool operator==(const SomeInnerClass &) const { return true; }
     };
 
     explicit Derived(int id = -1) noexcept;
index b8630eb1ec2e58e41821df87bd9f028f7d36e78c..0a28e877f3640470708ebe81a39b2a270976fa85 100644 (file)
@@ -34,7 +34,7 @@ void Point::show() const
     std::cout << "(x: " << m_x << ", y: " << m_y << ")";
 }
 
-bool Point::operator==(const Point &other)
+bool Point::operator==(const Point &other) const
 {
     return m_x == other.m_x && m_y == other.m_y;
 }
index 59e0236d5a76fd1bab6194e038406bbee20f9ccd..7e5d128abed20eb5b958e965500c496fff23b5a7 100644 (file)
@@ -38,7 +38,7 @@ public:
 
     // The != operator is not implemented for the purpose of testing
     // for the absense of the __ne__ method in the Python binding.
-    bool operator==(const Point &other);
+    bool operator==(const Point &other) const;
 
     Point operator+(const Point &other);
     Point operator-(const Point &other);
index 6b39f73a9b38517161fb2cbba703cb7778b422ab..736a5c6b597130e32c51aa9486579f72cb1a0bfd 100644 (file)
@@ -26,7 +26,7 @@ void PointF::show() const
     std::cout << "(x: " << m_x << ", y: " << m_y << ")";
 }
 
-bool PointF::operator==(const PointF &other)
+bool PointF::operator==(const PointF &other) const
 {
     return m_x == other.m_x && m_y == other.m_y;
 }
index bb50b5c6dae22b1e3b9d399cd15d6c23892d459d..49e00946781b010b356010cb888f24fd271c1c25 100644 (file)
@@ -31,7 +31,7 @@ public:
 
     // The != operator is not implemented for the purpose of testing
     // for the absence of the __ne__ method in the Python binding.
-    bool operator==(const PointF &other);
+    bool operator==(const PointF &other) const;
 
     PointF operator+(const PointF &other);
     PointF operator-(const PointF &other);
index a7b73cc81f5d4fca63cc70ca100c348a2ff9a2e6..1be93db667bd97612e5eb202b69558144af76ed4 100644 (file)
@@ -51,6 +51,26 @@ void StdSharedPtrTestBench::printInt(const std::shared_ptr<int> &p)
     std::cerr << '\n';
 }
 
+std::shared_ptr<std::string> StdSharedPtrTestBench::createString(const char *text)
+{
+    return std::make_shared<std::string>(text);
+}
+
+std::shared_ptr<std::string> StdSharedPtrTestBench::createNullString()
+{
+    return {};
+}
+
+void StdSharedPtrTestBench::printString(const std::shared_ptr<std::string> &p)
+{
+    std::cerr << __FUNCTION__ << ' ';
+    if (p.get())
+        std::cerr << '"' << *p << '"';
+    else
+        std::cerr << "nullptr";
+    std::cerr << '\n';
+}
+
 StdSharedPtrVirtualMethodTester::StdSharedPtrVirtualMethodTester() = default;
 StdSharedPtrVirtualMethodTester::~StdSharedPtrVirtualMethodTester() = default;
 
index 8991cded6df84a28b0cb2a25c08bc812d61c2fc9..04d75d5ef8b4fdfbcf0eaf7c6a68c5f8f9466352 100644 (file)
@@ -7,6 +7,7 @@
 #include "libsmartmacros.h"
 
 #include <memory>
+#include <string>
 
 class Integer;
 
@@ -23,6 +24,10 @@ public:
     static std::shared_ptr<int> createInt(int v = 42);
     static std::shared_ptr<int> createNullInt();
     static void printInt(const std::shared_ptr<int> &);
+
+    static std::shared_ptr<std::string> createString(const char *text);
+    static std::shared_ptr<std::string> createNullString();
+    static void printString(const std::shared_ptr<std::string> &);
 };
 
 class LIB_SMART_API StdSharedPtrVirtualMethodTester
index f625fc7763195f031f275ef92a2da1bdf457edf4..946a869dbc78ae6692ce6fa5fbd597604fd80a86 100644 (file)
@@ -11,7 +11,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from shiboken6 import Shiboken
+from shiboken6 import Shiboken  # noqa: F401
 
 from shibokensupport.signature.lib.tool import build_brace_pattern
 
@@ -21,8 +21,9 @@ against a slower reference implementation.
 The pattern is crucial, because it is used heavily in signature.parser .
 """
 
-# A slow reference parser for braces and strings
+
 def check(s):
+    """A slow reference parser for braces and strings"""
     open, close = "[{(<", "]})>"
     escape, quote = "\\", '"'
     instring = blind = False
@@ -41,8 +42,7 @@ def check(s):
             stack.append(c)
         elif c in close:
             pos = close.index(c)
-            if ((len(stack) > 0) and
-                (open[pos] == stack[len(stack)-1])):
+            if len(stack) > 0 and open[pos] == stack[len(stack) - 1]:
                 stack.pop()
             else:
                 return False
index 4d092b33cec64efda15b7a42ac3698f749e6f22c..b30bb653aa5e5abc1b844199b7e73f5dce1580a4 100644 (file)
@@ -32,7 +32,7 @@ class ExtListUser(ListUser):
         return [not mb1, not mb2]
 
     def oredMinBoolList(self, minBoolList):
-        return not reduce(lambda a, b: a|b, minBoolList)
+        return not reduce(lambda a, b: a | b, minBoolList)
 
     def createValList(self, num):
         return [Val(i) for i in range(0, num * 2, 2)]
@@ -303,14 +303,16 @@ class ListOfIntListConversionTest(unittest.TestCase):
     def testSumListOfIntListsFromExtendedClass(self):
         lu = ExtListUser()
         lst = [range(4)] * 4
-        self.assertEqual(lu.sumListOfIntLists(lst), sum([sum(line) for line in [range(4)] * 4]) * 2)
-        self.assertEqual(lu.callSumListOfIntLists(lst), sum([sum(line) for line in [range(4)] * 4]) * 2)
+        self.assertEqual(lu.sumListOfIntLists(lst),
+                         sum([sum(line) for line in [range(4)] * 4]) * 2)
+        self.assertEqual(lu.callSumListOfIntLists(lst),
+                         sum([sum(line) for line in [range(4)] * 4]) * 2)
 
     def testOpaqueContainer(self):
         lu = ListUser()
 
         # Set via Python
-        python_list = [1,2]
+        python_list = [1, 2]
         lu.setStdIntList(python_list)
         self.assertEqual(len(lu.m_stdIntList), 2)
         self.assertEqual(lu.m_stdIntList[0], 1)
@@ -331,8 +333,8 @@ class ListOfIntListConversionTest(unittest.TestCase):
         self.assertEqual(lu.m_stdIntList[2], 5)
 
         # Access list via getter
-        l = lu.getIntList()
-        l.append(6)
+        il = lu.getIntList()
+        il.append(6)
         self.assertEqual(len(lu.m_stdIntList), 4)
         self.assertEqual(lu.m_stdIntList[3], 6)
 
index 331b410b3625ee055588be89f8b8921ff61dd44c..d9ce0eac0b5f1136849e55d726c9302e8e7e0cdb 100644 (file)
@@ -13,32 +13,34 @@ init_paths()
 
 from minimal import MinBoolUser
 
+
 class DerivedMinBoolUser (MinBoolUser):
     def returnMyselfVirtual(self):
         return MinBoolUser()
 
+
 class MinBoolTest(unittest.TestCase):
 
     def testMinBoolUser(self):
         mbuTrue = MinBoolUser()
         mbuFalse = MinBoolUser()
         mbuTrue.setMinBool(True)
-        self.assertEqual(mbuFalse.minBool(), False)
-        self.assertEqual(mbuTrue.minBool(), True)
-        self.assertEqual(mbuTrue.callInvertedMinBool(), False)
+        self.assertFalse(mbuFalse.minBool())
+        self.assertTrue(mbuTrue.minBool())
+        self.assertFalse(mbuTrue.callInvertedMinBool())
 
-        self.assertEqual(mbuTrue.minBool() == True, True)
-        self.assertEqual(False == mbuFalse.minBool(), True)
-        self.assertEqual(mbuTrue.minBool() == mbuFalse.minBool(), False)
+        self.assertTrue(mbuTrue.minBool())
+        self.assertFalse(mbuFalse.minBool())
+        self.assertTrue(mbuTrue.minBool() != mbuFalse.minBool())
 
-        self.assertEqual(mbuFalse.minBool() != True, True)
-        self.assertEqual(True != mbuFalse.minBool(), True)
-        self.assertEqual(mbuTrue.minBool() != mbuFalse.minBool(), True)
+        self.assertFalse(mbuFalse.minBool())
+        self.assertFalse(mbuFalse.minBool())
+        self.assertTrue(mbuTrue.minBool() != mbuFalse.minBool())
 
     def testVirtuals(self):
         dmbu = DerivedMinBoolUser()
         self.assertEqual(dmbu.invertedMinBool(), True)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 0d8a2dced1ccf889927c6679f226d9c6ff47a41a..e873845dec4e94a3b1a20bdb0cc48889148a6352 100644 (file)
@@ -12,6 +12,7 @@ from shiboken_paths import init_paths
 init_paths()
 from minimal import Obj
 
+
 class ExtObj(Obj):
     def __init__(self, objId):
         Obj.__init__(self, objId)
@@ -91,4 +92,3 @@ class ObjTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 1d878be304f4172e8aad211dc10a6ee79182f0d5..c2fc8fc120d1b75788b4eb6f6fa6127e2bc10bc6 100644 (file)
@@ -2,7 +2,6 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
-from functools import reduce
 import os
 import sys
 import unittest
@@ -11,7 +10,9 @@ from pathlib import Path
 sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
-from minimal import *
+from minimal import (arrayFunc, arrayFuncInt, arrayFuncIntReturn,
+                     arrayFuncIntReturnTypedef, arrayFuncIntTypedef,
+                     arrayFuncReturn, arrayFuncReturnTypedef, arrayFuncTypedef)
 
 try:
     import numpy as np
@@ -31,29 +32,37 @@ class TypedefTest(unittest.TestCase):
         self.assertTrue(arrayFuncInt(none), "None is empty, arrayFuncInt should return true")
         self.assertFalse(arrayFuncInt(full), "Full is NOT empty, arrayFuncInt should return false")
 
-        self.assertTrue(arrayFuncInt(np.array(none)), "None is empty, arrayFuncInt should return true")
-        self.assertFalse(arrayFuncInt(np.array(full)), "Full is NOT empty, arrayFuncInt should return false")
+        self.assertTrue(arrayFuncInt(np.array(none)),
+                        "None is empty, arrayFuncInt should return true")
+        self.assertFalse(arrayFuncInt(np.array(full)),
+                         "Full is NOT empty, arrayFuncInt should return false")
 
     def test_arrayFuncIntTypedef(self):
         none = ()
         full = (1, 2, 3)
-        self.assertTrue(arrayFuncIntTypedef(none), "None is empty, arrayFuncIntTypedef should return true")
-        self.assertFalse(arrayFuncIntTypedef(full), "Full is NOT empty, arrayFuncIntTypedef should return false")
+        self.assertTrue(arrayFuncIntTypedef(none),
+                        "None is empty, arrayFuncIntTypedef should return true")
+        self.assertFalse(arrayFuncIntTypedef(full),
+                         "Full is NOT empty, arrayFuncIntTypedef should return false")
 
-        self.assertTrue(arrayFuncIntTypedef(np.array(none)), "None is empty, arrayFuncIntTypedef should return true")
-        self.assertFalse(arrayFuncIntTypedef(np.array(full)), "Full is NOT empty, arrayFuncIntTypedef should return false")
+        self.assertTrue(arrayFuncIntTypedef(np.array(none)),
+                        "None is empty, arrayFuncIntTypedef should return true")
+        self.assertFalse(arrayFuncIntTypedef(np.array(full)),
+                         "Full is NOT empty, arrayFuncIntTypedef should return false")
 
     def test_arrayFuncIntReturn(self):
         none = arrayFuncIntReturn(0)
         full = arrayFuncIntReturn(self.the_size)
         self.assertTrue((len(none) == 0), "none should be empty")
-        self.assertTrue((len(full) == self.the_size), "full should have " + str(self.the_size) + " elements")
+        self.assertTrue((len(full) == self.the_size),
+                        f"full should have {self.the_size} elements")
 
     def test_arrayFuncIntReturnTypedef(self):
         none = arrayFuncIntReturnTypedef(0)
         full = arrayFuncIntReturnTypedef(self.the_size)
         self.assertTrue((len(none) == 0), "none should be empty")
-        self.assertTrue((len(full) == self.the_size), "full should have " + str(self.the_size) + " elements")
+        self.assertTrue((len(full) == self.the_size),
+                        f"full should have {self.the_size} elements")
 
     def test_arrayFunc(self):
         none = ()
@@ -62,30 +71,37 @@ class TypedefTest(unittest.TestCase):
         self.assertFalse(arrayFunc(full), "Full is NOT empty, arrayFunc should return false")
 
         self.assertTrue(arrayFunc(np.array(none)), "None is empty, arrayFunc should return true")
-        self.assertFalse(arrayFunc(np.array(full)), "Full is NOT empty, arrayFunc should return false")
+        self.assertFalse(arrayFunc(np.array(full)),
+                         "Full is NOT empty, arrayFunc should return false")
 
     def test_arrayFuncTypedef(self):
         none = ()
         full = (1, 2, 3)
-        self.assertTrue(arrayFuncTypedef(none), "None is empty, arrayFuncTypedef should return true")
-        self.assertFalse(arrayFuncTypedef(full), "Full is NOT empty, arrayFuncTypedef should return false")
+        self.assertTrue(arrayFuncTypedef(none),
+                        "None is empty, arrayFuncTypedef should return true")
+        self.assertFalse(arrayFuncTypedef(full),
+                         "Full is NOT empty, arrayFuncTypedef should return false")
 
-        self.assertTrue(arrayFuncTypedef(np.array(none)), "None is empty, arrayFuncTypedef should return true")
-        self.assertFalse(arrayFuncTypedef(np.array(full)), "Full is NOT empty, arrayFuncTypedef should return false")
+        self.assertTrue(arrayFuncTypedef(np.array(none)),
+                        "None is empty, arrayFuncTypedef should return true")
+        self.assertFalse(arrayFuncTypedef(np.array(full)),
+                         "Full is NOT empty, arrayFuncTypedef should return false")
 
     def test_arrayFuncReturn(self):
         none = arrayFuncReturn(0)
         full = arrayFuncReturn(self.the_size)
         self.assertTrue((len(none) == 0), "none should be empty")
-        self.assertTrue((len(full) == self.the_size), "full should have " + str(self.the_size) + " elements")
+        self.assertTrue((len(full) == self.the_size),
+                        f"full should have {self.the_size} elements")
 
     def test_arrayFuncReturnTypedef(self):
         none = arrayFuncReturnTypedef(0)
         full = arrayFuncReturnTypedef(self.the_size)
         self.assertTrue((len(none) == 0), "none should be empty")
-        self.assertTrue((len(full) == self.the_size), "full should have " + str(self.the_size) + " elements")
+        self.assertTrue((len(full) == self.the_size),
+                        f"full should have {self.the_size} elements")
 
 
 if __name__ == '__main__':
-    if np != None:
+    if np is not None:
         unittest.main()
index 6403b5f14163d44953eae25f3dcd1bfb5c684aee..b8225a24712adf3b99910d076ab6f82f62d905e8 100644 (file)
@@ -92,4 +92,3 @@ class ValTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index ab9a6734527b395a11721edc12a10637c67b4a2b..2ba21653dd59b6deb782844466613e85e2a9941c 100644 (file)
@@ -16,6 +16,7 @@ init_paths()
 from sample import Collector, ObjectType
 from other import OtherObjectType
 
+
 class CollectorOtherObjectType(unittest.TestCase):
     '''Test cases for Collector << OtherObjectType'''
 
@@ -33,6 +34,6 @@ class CollectorOtherObjectType(unittest.TestCase):
         collector << obj
         self.assertEqual(collector.items()[0], obj.identifier() * 2)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 220cd3c98de020bc739b4a5bd02bf0cb3a53fe80..bd00b58922917a945f104c6177670949caa3390e 100644 (file)
@@ -18,8 +18,10 @@ init_paths()
 from sample import NoImplicitConversion
 from other import ExtendsNoImplicitConversion
 
+
 class ConversionOperatorForClassWithoutImplicitConversionsTest(unittest.TestCase):
-    '''Tests calling NoImplicitConversion constructor using a ExtendsNoImplicitConversion parameter.'''
+    '''Tests calling NoImplicitConversion constructor using a
+       ExtendsNoImplicitConversion parameter.'''
 
     def testNoImplicitConversion(self):
         '''Basic test to see if the NoImplicitConversion is Ok.'''
@@ -27,27 +29,33 @@ class ConversionOperatorForClassWithoutImplicitConversionsTest(unittest.TestCase
         # NoImplicitConversion.receivesNoImplicitConversionByValue(NoImplicitConversion)
         self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByValue(obj))
         # NoImplicitConversion.receivesNoImplicitConversionByPointer(NoImplicitConversion*)
-        self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByPointer(obj))
+        self.assertEqual(obj.objId(),
+                         NoImplicitConversion.receivesNoImplicitConversionByPointer(obj))
         # NoImplicitConversion.receivesNoImplicitConversionByReference(NoImplicitConversion&)
-        self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByReference(obj))
+        self.assertEqual(obj.objId(),
+                         NoImplicitConversion.receivesNoImplicitConversionByReference(obj))
 
     def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByValue(self):
-        '''Gives an ExtendsNoImplicitConversion object to a function expecting a NoImplicitConversion, passing by value.'''
+        '''Gives an ExtendsNoImplicitConversion object to a function expecting a
+           NoImplicitConversion, passing by value.'''
         obj = ExtendsNoImplicitConversion(123)
         self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByValue(obj))
 
     def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByReference(self):
-        '''Gives an ExtendsNoImplicitConversion object to a function expecting a NoImplicitConversion, passing by reference.'''
+        '''Gives an ExtendsNoImplicitConversion object to a function expecting a
+           NoImplicitConversion, passing by reference.'''
         obj = ExtendsNoImplicitConversion(123)
-        self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByReference(obj))
+        self.assertEqual(obj.objId(),
+                         NoImplicitConversion.receivesNoImplicitConversionByReference(obj))
 
     def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByPointer(self):
-        '''Gives an ExtendsNoImplicitConversion object to a function expecting a NoImplicitConversion, passing by pointer.
-           This should not be accepted, since pointers should not be converted.'''
+        '''Gives an ExtendsNoImplicitConversion object to a function expecting
+           a NoImplicitConversion, passing by pointer. This should not be
+           accepted, since pointers should not be converted.'''
         obj = ExtendsNoImplicitConversion(123)
-        self.assertRaises(TypeError, NoImplicitConversion.receivesNoImplicitConversionByPointer, obj)
+        self.assertRaises(TypeError,
+                          NoImplicitConversion.receivesNoImplicitConversionByPointer, obj)
 
 
 if __name__ == '__main__':
     unittest.main()
-
index 169f5259d9750d178d33fde6c7929771bba4ff0c..abbef623168f8cb45887937627c87f88ab0d92da 100644 (file)
@@ -16,6 +16,7 @@ init_paths()
 from sample import Point
 from other import Number
 
+
 class PointOperationsWithNumber(unittest.TestCase):
     '''Test cases for libsample's Point multiply operator defined in libother module.'''
 
@@ -39,6 +40,6 @@ class PointOperationsWithNumber(unittest.TestCase):
         num = Number(11)
         self.assertEqual(pt * num.value(), pt * 11)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 5be2b4191e427f53eb537043cc439954c3f9191e..bde2f52363d04e085355dbc907ea096f841b843e 100644 (file)
@@ -21,6 +21,7 @@ dst = workdir / 'test_module.py'
 shutil.copyfile(src, dst)
 sys.path.append(os.fspath(workdir))
 
+
 class TestModuleReloading(unittest.TestCase):
 
     def testModuleReloading(self):
@@ -32,5 +33,6 @@ class TestModuleReloading(unittest.TestCase):
             reload(test_module)
             self.assertFalse(oldObject is test_module.obj)
 
+
 if __name__ == "__main__":
     unittest.main()
index 5e3536c93beebc67fd4eec273ce98bbd54023ef3..d6c3564363f66ed0004f9cc399a6ae73976abb72 100644 (file)
@@ -2,7 +2,8 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
-'''Tests calling Str constructor using a Number parameter, being that number defines a cast operator to Str.'''
+'''Tests calling Str constructor using a Number parameter, being that number defines
+   a cast operator to Str.'''
 
 import os
 import sys
@@ -16,8 +17,10 @@ init_paths()
 from sample import Str
 from other import Number
 
+
 class NewCtorOperatorTest(unittest.TestCase):
-    '''Tests calling Str constructor using a Number parameter, being that number defines a cast operator to Str.'''
+    '''Tests calling Str constructor using a Number parameter, being that number
+       defines a cast operator to Str.'''
 
     def testNumber(self):
         '''Basic test to see if the Number class is Ok.'''
@@ -29,8 +32,8 @@ class NewCtorOperatorTest(unittest.TestCase):
         '''Try to build a Str from 'sample' module with a Number argument from 'other' module.'''
         value = 123
         num = Number(value)
-        string = Str(num)
+        string = Str(num)  # noqa: F841
+
 
 if __name__ == '__main__':
     unittest.main()
-
index d2c441058962cb436affb0edc2f254e1edf958aa..d2cd7de5ba63d35e7a105f236410d566a7ae727e 100644 (file)
@@ -9,10 +9,10 @@ from pathlib import Path
 sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
-from sample import *
-from other import *
+from sample import HandleHolder
 from shiboken6 import Shiboken
 
+
 class TestHashFuncs (unittest.TestCase):
 
     def testIt(self):
@@ -30,6 +30,5 @@ class TestHashFuncs (unittest.TestCase):
         self.assertEqual(hash1_2, hash1)
 
 
-
 if __name__ == '__main__':
     unittest.main()
index 1b876e1edbe959da355c43dbe1fa4fbec32015f7..459f474f11b9b358c7a7e4676e1091860d713400 100644 (file)
@@ -17,6 +17,7 @@ init_paths()
 from sample import Abstract, Derived
 from other import OtherDerived, Number
 
+
 class Multiple(Derived, Number):
     def __init__(self):
         Derived.__init__(self, 42)
@@ -25,6 +26,7 @@ class Multiple(Derived, Number):
     def testCall(self):
         return True
 
+
 class OtherDeviant(OtherDerived):
     def __init__(self):
         OtherDerived.__init__(self)
@@ -40,6 +42,7 @@ class OtherDeviant(OtherDerived):
     def className(self):
         return 'OtherDeviant'
 
+
 class MultipleTest(unittest.TestCase):
     '''Test case for Multiple derived class'''
 
@@ -58,6 +61,7 @@ class MultipleTest(unittest.TestCase):
         self.assertTrue(o.value(), 42)
         self.assertTrue(o.testCall())
 
+
 class OtherDerivedTest(unittest.TestCase):
     '''Test case for OtherDerived class'''
 
@@ -68,13 +72,15 @@ class OtherDerivedTest(unittest.TestCase):
         self.assertTrue(inherited_methods.issubset(dir(OtherDerived)))
 
     def testReimplementedPureVirtualMethodCall(self):
-        '''Test if a Python override of a implemented pure virtual method is correctly called from C++.'''
+        '''Test if a Python override of a implemented pure virtual method is
+           correctly called from C++.'''
         d = OtherDeviant()
         d.callPureVirtual()
         self.assertTrue(d.pure_virtual_called)
 
     def testReimplementedVirtualMethodCall(self):
-        '''Test if a Python override of a reimplemented virtual method is correctly called from C++.'''
+        '''Test if a Python override of a reimplemented virtual method is
+           correctly called from C++.'''
         d = OtherDeviant()
         d.callUnpureVirtual()
         self.assertTrue(d.unpure_virtual_called)
@@ -86,7 +92,8 @@ class OtherDerivedTest(unittest.TestCase):
         self.assertEqual(d.getClassName(), 'OtherDerived')
 
     def testReimplementedVirtualMethodCallReturningString(self):
-        '''Test if a Python override of a reimplemented virtual method is correctly called from C++.'''
+        '''Test if a Python override of a reimplemented virtual method is
+           correctly called from C++.'''
         d = OtherDeviant()
         self.assertEqual(d.className(), 'OtherDeviant')
         self.assertEqual(d.getClassName(), 'OtherDeviant')
@@ -97,6 +104,6 @@ class OtherDerivedTest(unittest.TestCase):
         d = OtherDerived(objId)
         self.assertEqual(Abstract.getObjectId(d), objId)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 9ac2456c070d7c107b47418a2af3d76d7de2ffbe..198c71693756f56665f1f52be0924c5c442a22f4 100644 (file)
@@ -13,8 +13,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from other import (OtherValueWithUnitUser, ValueWithUnitIntInch,
-                   ValueWithUnitIntMillimeter)
+from other import (OtherValueWithUnitUser, ValueWithUnitIntMillimeter)
 from sample import (ValueWithUnitDoubleMillimeter)
 
 
index 93f080e6db7346ddaaeec98480c3601f96669dd6..8db3e566b13aed6a00c006705c5fdb5024e1a4b6 100644 (file)
@@ -16,8 +16,6 @@ init_paths()
 from other import OtherObjectType
 from shiboken_test_helper import objectFullname
 
-from shiboken6 import Shiboken
-
 from shibokensupport.signature import get_signature
 
 
@@ -29,7 +27,7 @@ class SignatureTest(unittest.TestCase):
     def testNamespaceFromOtherModule(self):
         argType = get_signature(OtherObjectType.enumAsInt).parameters["value"].annotation
         self.assertEqual(objectFullname(argType),
-            "sample.SampleNamespace.SomeClass.PublicScopedEnum")
+                         "sample.SampleNamespace.SomeClass.PublicScopedEnum")
 
 
 if __name__ == '__main__':
index 6479e6337019982e76b806c32438542a83dc53ed..fd5c7fa09bc466350d78a5f8da6a4395a87c9dc2 100644 (file)
@@ -13,8 +13,6 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from smart import Integer
-from sample import Str
 from other import SmartPtrTester
 
 
diff --git a/sources/shiboken6/tests/otherbinding/star_import_test.py b/sources/shiboken6/tests/otherbinding/star_import_test.py
new file mode 100644 (file)
index 0000000..4b5f1d2
--- /dev/null
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+"""PYSIDE-2404: Test whether star imports work as they require special handling
+   by the lazy initialization."""
+
+import os
+import sys
+import unittest
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+SHIBOKEN_NAME = "shiboken6.Shiboken"
+MINIMAL_NAME = "minimal"
+OTHER_NAME = "other"
+
+shiboken_loaded = 1 if sys.modules.get(SHIBOKEN_NAME) else 0
+minimal_loaded = 1 if sys.modules.get(MINIMAL_NAME) else 0
+other_loaded = 1 if sys.modules.get(OTHER_NAME) else 0
+
+from minimal import *       # noqa: F403
+
+shiboken_loaded += 2 if sys.modules.get(SHIBOKEN_NAME) else 0
+minimal_loaded += 2 if sys.modules.get(MINIMAL_NAME) else 0
+other_loaded += 2 if sys.modules.get(OTHER_NAME) else 0
+
+from other import Number    # noqa: F403
+from other import *         # noqa: F403
+
+shiboken_loaded += 4 if sys.modules.get(SHIBOKEN_NAME) else 0
+minimal_loaded += 4 if sys.modules.get(MINIMAL_NAME) else 0
+other_loaded = +4 if sys.modules.get(OTHER_NAME) else 0
+
+import shiboken6.Shiboken   # noqa: F401 F403
+
+shiboken_loaded += 8 if sys.modules.get(SHIBOKEN_NAME) else 0
+
+
+class ValTest(unittest.TestCase):
+
+    def test(self):
+        val_id = 123
+        val = Val(val_id)  # noqa: F405
+        self.assertEqual(val.valId(), val_id)
+
+
+class Simple(Number):
+
+    def __init__(self):
+        Number.__init__(self, 42)
+
+
+class OtherTest(unittest.TestCase):
+
+    def testConstructor(self):
+        o = Simple()
+        self.assertTrue(isinstance(o, Number))
+
+
+class StarImportTest(unittest.TestCase):
+    """
+    This test is meant for Lazy Init.
+    We explicitly choose modules which are able to lazy load.
+
+    The ValTest:
+    ------------
+    We load something with `import *`.
+    There is no module from our known ones imported.
+    This means we need stack introspection to find out that this was
+    a star import and we must disable lazyness.
+
+    The OtherTest:
+    --------------
+    We load something normally that should be lazy.
+    After that, we follow with a star import.
+    Now the stack introspection does not work, because the loading is
+    cached. The first import did a lazy load. The following star import
+    needs to undo the lazyness. But now we have a redirected import.
+
+    All tests simply check if the objects are real and not just names.
+    The <module>_loaded tests prevend upcoming internal dependencies.
+
+    To make sure that Shiboken is really not involved, it is checked
+    and really imported afterwards (ensuring nothing is misspelled).
+    """
+
+    def testStar(self):
+        self.assertEqual(other_loaded, 4)
+        self.assertEqual(minimal_loaded, 6)
+        self.assertEqual(shiboken_loaded, 14)
+        # Interesting effect: Did not expect that shiboken is loaded at all.
+
+
+if __name__ == '__main__':
+    unittest.main()
index 183ba9fe5f58d08adbc5735efc012bce1b5c4775..36ab43ae3fc7869ef76b1e0ba4b3447326d8c51c 100644 (file)
@@ -1,13 +1,22 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
-from other import *
-from sample import *
+import os
+import sys
+
+from pathlib import Path
+sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
+from shiboken_paths import init_paths
+init_paths()
+
+from other import OtherObjectType
+from sample import ObjectType
 
 
 class MyObjectType(ObjectType):
     pass
 
+
 class MyOtherObjectType(OtherObjectType):
     value = 10
 
index 51fc7c01be983edad6793d561c52bf54aef14e0e..791d3bdce52d48a680af2939af8d115e56dfc3a5 100644 (file)
@@ -13,9 +13,10 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import Abstract, Base1, Derived, MDerived1, MDerived3, SonOfMDerived1
+from sample import Abstract, Base1, Derived
 from other import OtherMultipleDerived
 
+
 class TypeDiscoveryTest(unittest.TestCase):
 
     def testPureVirtualsOfImpossibleTypeDiscovery(self):
@@ -29,18 +30,19 @@ class TypeDiscoveryTest(unittest.TestCase):
         self.assertEqual(type(a), Derived)
 
     def testMultipleInheritance(self):
-        obj = OtherMultipleDerived.createObject("Base1");
+        obj = OtherMultipleDerived.createObject("Base1")
         self.assertEqual(type(obj), Base1)
         # PYSIDE-868: In case of multiple inheritance, a factory
         # function will return the base class wrapper.
-        obj = OtherMultipleDerived.createObject("MDerived1");
+        obj = OtherMultipleDerived.createObject("MDerived1")
         self.assertEqual(type(obj), Base1)
-        obj = OtherMultipleDerived.createObject("SonOfMDerived1");
+        obj = OtherMultipleDerived.createObject("SonOfMDerived1")
         self.assertEqual(type(obj), Base1)
-        obj = OtherMultipleDerived.createObject("MDerived3");
+        obj = OtherMultipleDerived.createObject("MDerived3")
         self.assertEqual(type(obj), Base1)
-        obj = OtherMultipleDerived.createObject("OtherMultipleDerived");
+        obj = OtherMultipleDerived.createObject("OtherMultipleDerived")
         self.assertEqual(type(obj), Base1)
 
+
 if __name__ == '__main__':
     unittest.main()
index b464fa566f5c78c6dd28904a9035cd94615f73a7..15a988326037e5fec6d012bf37f13fa0ad2c35af 100644 (file)
@@ -14,6 +14,7 @@ from shiboken_paths import init_paths
 init_paths()
 from other import Number
 
+
 class UserDefinedPrimitiveTypeFromRequiredModuleTest(unittest.TestCase):
 
     def testUsersPrimitiveFromRequiredModuleAsArgument(self):
@@ -28,5 +29,6 @@ class UserDefinedPrimitiveTypeFromRequiredModuleTest(unittest.TestCase):
         cpx = number.toComplex()
         self.assertEqual(number.value(), int(cpx.real))
 
+
 if __name__ == '__main__':
     unittest.main()
index 9aacfa9ac9e8ae194c36e3c424ce5008a353ca6c..b9251b428ba8bb32080c20a0cba56f801abe7c89 100644 (file)
@@ -10,17 +10,19 @@ from pathlib import Path
 sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
-from sample import *
-from other import *
+from sample import Abstract, ObjectType
+from other import OtherDerived
+
 
 class Foo(OtherDerived):
     def __init__(self):
-        Abstract.__init__(self, 2) # this should raise an exception
+        Abstract.__init__(self, 2)  # this should raise an exception
+
 
 class Foo2(ObjectType, OtherDerived):
     def __init__(self):
         ObjectType.__init__(self)
-        Abstract.__init__(self, 2) # this should raise an exception
+        Abstract.__init__(self, 2)  # this should raise an exception
 
 
 class WrongCtorTest(unittest.TestCase):
index c877c3ba3fd48f748adf12ef17f1bb9ad9d8e640..45cecd1a190378ae0f4f6e945921f78a609b0a4a 100644 (file)
@@ -464,7 +464,7 @@ void QtXmlToSphinxTest::testTableFormattingIoDevice()
 void QtXmlToSphinxTest::testSnippetExtraction_data()
 {
     QTest::addColumn<QByteArray>("file");
-    QTest::addColumn<QString>("id");
+    QTest::addColumn<QLatin1StringView>("id");
     QTest::addColumn<QString>("expected");
 
     const char *fileCpp = R"(bla
@@ -476,7 +476,7 @@ snip2_line2
 // ![snip2] // ![snip3]
 )";
 
-    const QString id = u"snip2"_s;
+    constexpr auto id = "snip2"_L1;
     const QString expected  = uR"(snip2_line1
 snip2_line2
 )"_s;
@@ -497,7 +497,7 @@ snip2_line2
 void QtXmlToSphinxTest::testSnippetExtraction()
 {
     QFETCH(QByteArray, file);
-    QFETCH(QString, id);
+    QFETCH(QLatin1StringView, id);
     QFETCH(QString, expected);
 
     QBuffer buffer(&file);
index 2d38b24d7fbdda377b5e28c44e1d5e959cbeb5be..456886614b4a291b158eeeede6e22a8803425e69 100644 (file)
@@ -16,11 +16,13 @@ import sample
 
 delCalled = False
 
+
 class MyObject(sample.ObjectType):
     def __del__(self):
         global delCalled
         delCalled = True
 
+
 class TestDel(unittest.TestCase):
     def testIt(self):
         a = MyObject()
@@ -29,6 +31,6 @@ class TestDel(unittest.TestCase):
         gc.collect()
         self.assertTrue(delCalled)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 252541af157232e27d31c0bb4b6bbc7fcab03183..89e87be1d794d23bd102a4e99c1352f2ffbb292c 100644 (file)
@@ -15,10 +15,12 @@ init_paths()
 
 from sample import Abstract
 
+
 class Incomplete(Abstract):
     def __init__(self):
         Abstract.__init__(self)
 
+
 class Concrete(Abstract):
     def __init__(self):
         Abstract.__init__(self)
@@ -60,12 +62,7 @@ class AbstractTest(unittest.TestCase):
         # Python and calling it from C++ is undefined until it's decided how to
         # cast the Python data types to void pointers
         c = Concrete()
-        self.assertEqual(c.pureVirtualReturningVoidPtr(),42)
-
-    def testReimplementedVirtualMethodCall(self):
-        '''Test if instanciation of an abstract class raises the correct exception.'''
-        i = Concrete()
-        self.assertRaises(NotImplementedError, i.callPureVirtual)
+        self.assertEqual(c.pureVirtualReturningVoidPtr(), 42)
 
     def testReimplementedVirtualMethodCall(self):
         '''Test if a Python override of a virtual method is correctly called from C++.'''
@@ -85,6 +82,6 @@ class AbstractTest(unittest.TestCase):
         c.callVirtualGettingEnum(Abstract.Short)
         self.assertTrue(c.virtual_getting_enum)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 879bba7f2a03a7dc9f1fbe24502faca8e8421401..0b5680143dbfb4ff7ce88f9b560f09405f83a05f 100644 (file)
@@ -14,6 +14,7 @@ from shiboken_paths import init_paths
 init_paths()
 from sample import SampleNamespace, ObjectType, Point
 
+
 class TestAddedFunctionsWithSimilarTypes(unittest.TestCase):
     '''Adds new signatures very similar to already existing ones.'''
 
@@ -38,5 +39,6 @@ class TestAddedFunctionsWithSimilarTypes(unittest.TestCase):
         control = len(obj.objectName())
         self.assertEqual(SampleNamespace.passReferenceToObjectType(obj), control)
 
+
 if __name__ == '__main__':
     unittest.main()
index 3a570ccfd789e17544d91791d13da92d345e5269..2a739033bff3189c7c69de0a4584db66e1e05f82 100644 (file)
@@ -14,18 +14,20 @@ from shiboken_paths import init_paths
 init_paths()
 from sample import sum2d, sumproduct
 
+
 class TestAddedFunctionsWithContainerArgs(unittest.TestCase):
     '''Tests added functions with nested and multi-argument container types.'''
 
     def testNestedContainerType(self):
         '''Test added function with single-argument containers.'''
-        values = [[1,2],[3,4,5],[6]]
+        values = [[1, 2], [3, 4, 5], [6]]
         self.assertEqual(sum2d(values), 21)
 
     def testMultiArgContainerType(self):
         '''Test added function with a two-argument container.'''
-        values = [(1,2),(3,4),(5,6)]
+        values = [(1, 2), (3, 4), (5, 6)]
         self.assertEqual(sumproduct(values), 44)
 
+
 if __name__ == '__main__':
     unittest.main()
index 8158f89d2c1b1f43ccc66c385e8918dfd7b7a6f1..b0ca56a6d1d9a8e3011f57c6f83409f65e7ec264 100644 (file)
@@ -16,6 +16,7 @@ init_paths()
 
 from sample import Modifications, Point
 
+
 class ArgumentModificationsTest(unittest.TestCase):
     '''Test cases for method arguments modifications performed as described on typesystem.'''
 
@@ -40,7 +41,8 @@ class ArgumentModificationsTest(unittest.TestCase):
 
     def testArgRemoval1(self):
         '''Tests argument removal modifications on Modifications.argRemoval1.'''
-        # void [-> PyObject*] argRemoval1(int, bool, Point = Point(1, 2) [removed], Point = Point(3, 4) [removed], int = 333)
+        # void [-> PyObject*] argRemoval1(int, bool, Point = Point(1, 2) [removed],
+        #      Point = Point(3, 4) [removed], int = 333)
         # code-injection: returns tuple with received parameters plus removed ones
         a0, a1, a2 = 1, True, 2
         self.assertEqual(self.mods.argRemoval1(a0, a1), (a0, a1, Point(1, 2), Point(3, 4), 333))
@@ -51,7 +53,8 @@ class ArgumentModificationsTest(unittest.TestCase):
 
     def testArgRemoval2(self):
         '''Tests argument removal modifications on Modifications.argRemoval2.'''
-        # void [-> PyObject*] argRemoval2(int, bool, Point = Point(1, 2) [removed], Point = Point(3, 4) [removed], int = 333)
+        # void [-> PyObject*] argRemoval2(int, bool, Point = Point(1, 2)
+        #      [removed], Point = Point(3, 4) [removed], int = 333)
         # code-injection: returns tuple with received parameters plus removed ones
         a0, a1, a2 = 1, True, 2
         self.assertEqual(self.mods.argRemoval2(a0, a1), (a0, a1, Point(1, 2), Point(3, 4), 333))
@@ -59,7 +62,8 @@ class ArgumentModificationsTest(unittest.TestCase):
 
     def testArgRemoval3(self):
         '''Tests argument removal modifications on Modifications.argRemoval3.'''
-        # void [-> PyObject*] argRemoval3(int, Point = Point(1, 2) [removed], bool = true, Point = Point(3, 4) [removed], int = 333)
+        # void [-> PyObject*] argRemoval3(int, Point = Point(1, 2) [removed],
+        #      bool = true, Point = Point(3, 4) [removed], int = 333)
         # code-injection: returns tuple with received parameters plus removed ones
         a0, a1, a2 = 1, True, 2
         self.assertEqual(self.mods.argRemoval3(a0), (a0, Point(1, 2), True, Point(3, 4), 333))
@@ -68,7 +72,8 @@ class ArgumentModificationsTest(unittest.TestCase):
 
     def testArgRemoval4(self):
         '''Tests argument removal modifications on Modifications.argRemoval4.'''
-        # void [-> PyObject*] argRemoval4(int, Point [removed, new val = Point(6, 9)], bool, Point = Point(3, 4) [removed], int = 333)
+        # void [-> PyObject*] argRemoval4(int, Point [removed, new val = Point(6, 9)], bool,
+        #      Point = Point(3, 4) [removed], int = 333)
         # code-injection: returns tuple with received parameters plus removed ones
         a0, a1, a2 = 1, True, 2
         self.assertRaises(TypeError, self.mods.argRemoval4, a0)
@@ -88,6 +93,6 @@ class ArgumentModificationsTest(unittest.TestCase):
         # code-injection: returns tuple with received parameters plus removed ones
         self.assertEqual(self.mods.argRemoval5(a0, a1, a2), (200, a0, a1, a2))
 
+
 if __name__ == '__main__':
     unittest.main()
-
index ba9194122988d85617a56a644858f8bfc86ff3ff..0d73bca1c97b30d34d9492c50727775ac7f27ab7 100644 (file)
@@ -22,24 +22,26 @@ try:
 except ImportError:
     pass
 
+
 class ArrayTester(unittest.TestCase):
     '''Test case for NumPy arrays.'''
 
     def testIntArray(self):
-        intList = numpy.array([1, 2, 3, 4], dtype = 'int32')
+        intList = numpy.array([1, 2, 3, 4], dtype='int32')
         self.assertEqual(sample.sumIntArray(intList), 10)
 
     def testDoubleArray(self):
-        doubleList = numpy.array([1, 2, 3, 4], dtype = 'double')
+        doubleList = numpy.array([1, 2, 3, 4], dtype='double')
         self.assertEqual(sample.sumDoubleArray(doubleList), 10)
 
     def testIntMatrix(self):
-        intMatrix = numpy.array([[1, 2, 3], [4, 5, 6]], dtype = 'int32')
+        intMatrix = numpy.array([[1, 2, 3], [4, 5, 6]], dtype='int32')
         self.assertEqual(sample.sumIntMatrix(intMatrix), 21)
 
     def testDoubleMatrix(self):
-        doubleMatrix = numpy.array([[1, 2, 3], [4, 5, 6]], dtype = 'double')
+        doubleMatrix = numpy.array([[1, 2, 3], [4, 5, 6]], dtype='double')
         self.assertEqual(sample.sumDoubleMatrix(doubleMatrix), 21)
 
+
 if __name__ == '__main__' and hasNumPy:
     unittest.main()
index cb5cbc49d155d32b4874ca78fac2ac1f8257e89c..ad65d58db625337d1ebf1837857ab79aaeec8c24 100644 (file)
@@ -14,6 +14,7 @@ from shiboken_paths import init_paths
 init_paths()
 import sample
 
+
 class ArrayTester(unittest.TestCase):
     '''Test case for arrays.'''
 
@@ -30,5 +31,6 @@ class ArrayTester(unittest.TestCase):
         doubleList = [1.2, 2.3, 3.4, 4.5]
         self.assertEqual(sample.sumDoubleArray(doubleList), 11.4)
 
+
 if __name__ == '__main__':
     unittest.main()
index 6c4df6399349ab9f7899e688850815728de1ba39..a7e7a7210a59bb1460b136e541f0108055b35007 100644 (file)
@@ -11,15 +11,15 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import ObjectType
+
 
 class Bug554:
     def crash(self):
         class Crasher(ObjectType):
             pass
 
+
 if __name__ == '__main__':
     bug = Bug554()
     bug.crash()
-
-
index 6de8fa3ea6a3c771bc46cc87f47c8ef23dea3cae..c470fe7239b08c2af4eefcf2eb791a2bfe960a33 100644 (file)
@@ -25,13 +25,12 @@ def defineNewStyle():
 
 
 class ObjectTypeTest(unittest.TestCase):
-    '''Test cases to avoid declaring Shiboken classes with multiple inheritance from old style classes.'''
+    '''Test cases to avoid declaring Shiboken classes with multiple inheritance
+       from old style classes.'''
 
     def testObjectTypeNewStype(self):
         defineNewStyle()
 
 
-
 if __name__ == '__main__':
     unittest.main()
-
index e7c421b965cc454cc639cc0f073ec318330ce41e..e51a899faeb31a1f55efea53b91abde56d065810 100644 (file)
@@ -34,7 +34,7 @@ class ByteArrayConcatenationOperatorTest(unittest.TestCase):
 
     def testConcatPythonStringAndByteArray(self):
         # Test concatenation of a Python string with a ByteArray, in this order.
-        concat_python_string_add_qbytearray_worked = True
+        concat_python_string_add_qbytearray_worked = True  # noqa: F841
         ba = ByteArray('foo')
         result = 'bar\x00' + ba
         self.assertEqual(type(result), ByteArray)
@@ -80,14 +80,14 @@ class ByteArrayOperatorAt(unittest.TestCase):
         # ByteArray[x] where x is a valid index (reverse order).
         string = 'abcdefgh'
         obj = ByteArray(string)
-        for i in range(len(string)-1, 0, -1):
+        for i in range(len(string) - 1, 0, -1):
             self.assertEqual(obj[i], bytes(string[i], "UTF8"))
 
     def testOutOfRange(self):
         # ByteArray[x] where x is out of index.
         string = '1234567'
         obj = ByteArray(string)
-        self.assertRaises(IndexError, lambda :obj[len(string)])
+        self.assertRaises(IndexError, lambdaobj[len(string)])
 
     def testNullStrings(self):
         ba = ByteArray('\x00')
index 97525bcb83b21d69d3f42376cfe65e9c298b7106..f0ac706264cd417528f33f8ddf115522d3b563ce 100644 (file)
@@ -14,7 +14,8 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import ObjectType
+
 
 class ReturnOfChildTest(unittest.TestCase):
     '''The BlackBox class has cases of ownership transference between C++ and Python.'''
@@ -37,6 +38,6 @@ class ReturnOfChildTest(unittest.TestCase):
         gc.collect()
         self.assertRaises(RuntimeError, child.objectName)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 9da25e1373f2f8d9c3f4bc86cf8f0c335737d139..1eeb3d44679ed5b9f7ff01fc8119db48a8820c72 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import Derived, Point, ObjectType
 
+
 class TestAccessingCppFields(unittest.TestCase):
     '''Simple test case for accessing the exposed C++ class fields.'''
 
@@ -36,7 +37,7 @@ class TestAccessingCppFields(unittest.TestCase):
         self.assertEqual(d.primitiveField, int(value))
 
         # attribution with invalid type
-        self.assertRaises(TypeError, lambda : setattr(d, 'primitiveField', None))
+        self.assertRaises(TypeError, lambda: setattr(d, 'primitiveField', None))
 
     def testAccessingRenamedFields(self):
         '''Reads and writes a renamed field.'''
@@ -72,7 +73,7 @@ class TestAccessingCppFields(unittest.TestCase):
         self.assertNotEqual(d.userPrimitiveField, old_value)
 
         # attribution with invalid type
-        self.assertRaises(TypeError, lambda : setattr(d, 'userPrimitiveField', None))
+        self.assertRaises(TypeError, lambda: setattr(d, 'userPrimitiveField', None))
 
     def testAccessingValueTypeField(self):
         '''Reads and writes a value type (in this case a 'Point') field.'''
@@ -80,7 +81,7 @@ class TestAccessingCppFields(unittest.TestCase):
         self.assertEqual(type(d.valueTypeField), Point)
 
         # attribution
-        old_value = d.valueTypeField
+        old_value = d.valueTypeField  # noqa: F841
         new_value = Point(-10, 537)
         d.valueTypeField = new_value
         self.assertEqual(d.valueTypeField, new_value)
@@ -92,7 +93,7 @@ class TestAccessingCppFields(unittest.TestCase):
         self.assertEqual(d.valueTypeField.y(), 20)
 
         # attribution with invalid type
-        self.assertRaises(TypeError, lambda : setattr(d, 'valueTypeField', 123))
+        self.assertRaises(TypeError, lambda: setattr(d, 'valueTypeField', 123))
 
     def testAccessingObjectTypeField(self):
         '''Reads and writes a object type (in this case an 'ObjectType') field.'''
@@ -111,7 +112,7 @@ class TestAccessingCppFields(unittest.TestCase):
         self.assertEqual(d.objectTypeField, value)
 
         # attribution with invalid type
-        self.assertRaises(TypeError, lambda : setattr(d, 'objectTypeField', 123))
+        self.assertRaises(TypeError, lambda: setattr(d, 'objectTypeField', 123))
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testRefCountingAccessingObjectTypeField(self):
@@ -155,7 +156,7 @@ class TestAccessingCppFields(unittest.TestCase):
         # attribution
         old_value = d.bitField
         new_value = 1
-        d.bitField= new_value
+        d.bitField = new_value
         self.assertEqual(d.bitField, new_value)
         self.assertNotEqual(d.bitField, old_value)
 
@@ -165,7 +166,7 @@ class TestAccessingCppFields(unittest.TestCase):
         self.assertEqual(d.bitField, int(value))
 
         # attribution with invalid type
-        self.assertRaises(TypeError, lambda : setattr(d, 'bitField', None))
+        self.assertRaises(TypeError, lambda: setattr(d, 'bitField', None))
 
 
 if __name__ == '__main__':
index 376f91f1cb1364a7f4fe5a8357400df9c945de2d..4caebc62a2525ea5d56a53cccdb2244b04e6e4a9 100644 (file)
@@ -33,6 +33,7 @@ class CollectorTest(unittest.TestCase):
         self.assertEqual(collector.size(), 5)
         self.assertEqual(collector.items(), [2, 3, 5, 7, 11])
 
+
 class CollectorExternalOperator(unittest.TestCase):
     '''Test cases for external operators of Collector'''
 
@@ -57,4 +58,3 @@ class CollectorObjectType(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 6f0b23b2a20c37d84f104791cd47323486496df2..454aff100b4c1bfd526bcaff1d4c11ccc809bf5b 100644 (file)
@@ -16,6 +16,7 @@ init_paths()
 import sample
 from sample import Point
 
+
 class ComplexTest(unittest.TestCase):
     '''Test case for conversions between C++ Complex class to Python complex class'''
 
@@ -47,11 +48,14 @@ class ComplexTest(unittest.TestCase):
 
     def testUsingTuples(self):
         cpx1, cpx2 = (1.2, 3.4), (5.6, 7.8)
-        self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), sample.sumComplexPair((complex(*cpx1), complex(*cpx2))))
+        self.assertEqual(sample.sumComplexPair((cpx1, cpx2)),
+                         sample.sumComplexPair((complex(*cpx1), complex(*cpx2))))
         cpx1, cpx2 = (1, 3), (5, 7)
-        self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), sample.sumComplexPair((complex(*cpx1), complex(*cpx2))))
+        self.assertEqual(sample.sumComplexPair((cpx1, cpx2)),
+                         sample.sumComplexPair((complex(*cpx1), complex(*cpx2))))
         cpx1, cpx2 = (1.2, 3), (5.6, 7)
-        self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), sample.sumComplexPair((complex(*cpx1), complex(*cpx2))))
+        self.assertEqual(sample.sumComplexPair((cpx1, cpx2)),
+                         sample.sumComplexPair((complex(*cpx1), complex(*cpx2))))
         cpx1, cpx2 = (1, 2, 3), (4, 5, 7)
         self.assertRaises(TypeError, sample.sumComplexPair, (cpx1, cpx2))
         cpx1, cpx2 = ('1', '2'), ('4', '5')
@@ -60,4 +64,3 @@ class ComplexTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index f349ae82bc6e741b687275ea36cad3dd9a0af1a8..7e76245b103482e42f8e6cec5f7cc52a5a30c379 100644 (file)
@@ -15,11 +15,13 @@ init_paths()
 
 from sample import Time, StrList
 
+
 class ConversionOperatorTest(unittest.TestCase):
     '''Test cases for implicit conversion generated by conversion operator.'''
 
     def testConversionOperator(self):
-        '''Time defined an conversion operator for Str, so passing a Time object to a method expecting a Str should work.'''
+        '''Time defined an conversion operator for Str, so passing a Time object
+           to a method expecting a Str should work.'''
         t = Time(1, 2, 3)
         t_str = t.toString()
         sl = StrList()
@@ -30,6 +32,6 @@ class ConversionOperatorTest(unittest.TestCase):
         self.assertEqual(len(sl), 1)
         self.assertEqual(sl[0], t_str)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 0a0533a41bba688f96983a6f41b081b1e4fa1fdd..db539d1b902e63a4e2bf8c9faaa3f06ec90304b6 100644 (file)
@@ -63,4 +63,3 @@ class PicklingTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 0ad21e35c1174bd4081b4bbbb5cb9a2cca718ee4..5e2695d7218249a88eeea0ef238cc081acda974f 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import CtorConvRule
 
+
 class TestCtorConvRule(unittest.TestCase):
     '''Simple test case for CtorConvRule'''
 
@@ -24,6 +25,6 @@ class TestCtorConvRule(unittest.TestCase):
         obj = CtorConvRule(value)
         self.assertEqual(obj.value(), value + 1)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index b72e41b1970fc8b81826e32c674deaa8af8bf342..4e4ae26032e49168eecae265be9a92b8fea7b725 100644 (file)
@@ -16,7 +16,6 @@ from sample import ObjectView
 from sample import ObjectModel
 
 
-
 class ObjTest(unittest.TestCase):
 
     def test_cyclic_dependency_withParent(self):
@@ -37,7 +36,7 @@ class ObjTest(unittest.TestCase):
         # turn off automatic garbage collection, to be able to trigger it
         # at the 'right' time
         gc.disable()
-        alive = lambda :sum(isinstance(o, CyclicObject) for o in gc.get_objects() )
+        alive = lambda: sum(isinstance(o, CyclicObject) for o in gc.get_objects())  # noqa: E731
 
         #
         # first proof that the wizard is only destructed by the garbage
@@ -70,7 +69,7 @@ class ObjTest(unittest.TestCase):
         # turn off automatic garbage collection, to be able to trigger it
         # at the 'right' time
         gc.disable()
-        alive = lambda :sum(isinstance(o, CyclicObject) for o in gc.get_objects() )
+        alive = lambda: sum(isinstance(o, CyclicObject) for o in gc.get_objects())  # noqa: E731
 
         #
         # first proof that the wizard is only destructed by the garbage
@@ -85,6 +84,6 @@ class ObjTest(unittest.TestCase):
         gc.collect()
         self.assertFalse(alive())
 
+
 if __name__ == '__main__':
     unittest.main()
-
index a35861c8c8e0e253221d59d6ba2c5546cb0f0902..2b6efcf1865cecb7961f74788c30567158217c6c 100644 (file)
@@ -16,6 +16,7 @@ from datetime import date
 
 from sample import SbkDate
 
+
 class DateConversionTest(unittest.TestCase):
 
     def testConstructorWithDateObject(self):
@@ -32,6 +33,6 @@ class DateConversionTest(unittest.TestCase):
         self.assertTrue(cDate.month(), pyDate.month)
         self.assertTrue(cDate.year(), pyDate.year)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 6c7b4482d7e22b63f8550140ef71f7e786cc8bf6..0d39c5f96861ba2d9876b6823de370c08f859c26 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import SampleNamespace, Point, ObjectType, ObjectModel
 
+
 class DecisorTest(unittest.TestCase):
     '''Test cases for the method overload decisor.'''
 
@@ -37,11 +38,15 @@ class DecisorTest(unittest.TestCase):
         '''Call methods overloads that receive parent and inheritor classes' instances.'''
         objecttype = ObjectType()
         objectmodel = ObjectModel()
-        self.assertEqual(ObjectModel.receivesObjectTypeFamily(objecttype), ObjectModel.ObjectTypeCalled)
-        self.assertNotEqual(ObjectModel.receivesObjectTypeFamily(objecttype), ObjectModel.ObjectModelCalled)
-        self.assertEqual(ObjectModel.receivesObjectTypeFamily(objectmodel), ObjectModel.ObjectModelCalled)
-        self.assertNotEqual(ObjectModel.receivesObjectTypeFamily(objectmodel), ObjectModel.ObjectTypeCalled)
+        self.assertEqual(ObjectModel.receivesObjectTypeFamily(objecttype),
+                         ObjectModel.ObjectTypeCalled)
+        self.assertNotEqual(ObjectModel.receivesObjectTypeFamily(objecttype),
+                            ObjectModel.ObjectModelCalled)
+        self.assertEqual(ObjectModel.receivesObjectTypeFamily(objectmodel),
+                         ObjectModel.ObjectModelCalled)
+        self.assertNotEqual(ObjectModel.receivesObjectTypeFamily(objectmodel),
+                            ObjectModel.ObjectTypeCalled)
+
 
 if __name__ == '__main__':
     unittest.main()
-
index 5a4ee090e4198c2ae714171e3bae1cde9a7d0481..57a792ae274100b9eb6dc207db3b290bb289d731 100644 (file)
@@ -14,15 +14,15 @@ init_paths()
 import sample
 from shiboken6 import Shiboken
 
+
 class DeleteTest(unittest.TestCase):
     def testNonCppWrapperClassDelete(self):
-        """Would segfault when shiboken.delete called on obj not created from
-        Python """
+        """Would segfault when shiboken.delete called on obj not created from Python."""
         obj = sample.ObjectType()
         child = obj.createChild(None)
         Shiboken.delete(child)
         assert not Shiboken.isValid(child)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 95b07f838acbffed6c45e88895ab34cd3e5027ec..c371df94f03553d65db0adf41d3ff720e2f89d52 100644 (file)
@@ -14,11 +14,13 @@ init_paths()
 
 from sample import ObjectType
 
+
 class TestDeprecatedCall(unittest.TestCase):
     def testCallWithError(self):
         o = ObjectType()
         warnings.simplefilter('error')
         self.assertRaises(DeprecationWarning, o.deprecatedFunction)
 
+
 if __name__ == '__main__':
     unittest.main()
index a92ccd311fcda6802d0c72abf45638798e50b265..346f29136c30f7783271d3dd88ecda50fb8bcc5d 100644 (file)
@@ -16,6 +16,7 @@ init_paths()
 import sample
 from sample import Abstract, Derived, DerivedUsingCt, OverloadedFuncEnum
 
+
 class Deviant(Derived):
     def __init__(self):
         Derived.__init__(self)
@@ -31,6 +32,16 @@ class Deviant(Derived):
     def className(self):
         return 'Deviant'
 
+
+class ImplementVirtualWithOutParameter(Derived):
+    def __init__(self, value):
+        super().__init__()
+        self._value = value
+
+    def virtualWithOutParameter(self):
+        return self._value
+
+
 class DerivedTest(unittest.TestCase):
     '''Test case for Derived class'''
 
@@ -59,18 +70,21 @@ class DerivedTest(unittest.TestCase):
         self.assertEqual(type(result), OverloadedFuncEnum)
 
     def testOverloadedMethodCallWithWrongNumberOfArguments(self):
-        '''Test if a call to an overloaded method with the wrong number of arguments raises an exception.'''
+        '''Test if a call to an overloaded method with the wrong number of arguments
+           raises an exception.'''
         derived = Derived()
         self.assertRaises(TypeError, derived.otherOverloaded, 1, 2, True)
 
     def testReimplementedPureVirtualMethodCall(self):
-        '''Test if a Python override of a implemented pure virtual method is correctly called from C++.'''
+        '''Test if a Python override of a implemented pure virtual method is
+           correctly called from C++.'''
         d = Deviant()
         d.callPureVirtual()
         self.assertTrue(d.pure_virtual_called)
 
     def testReimplementedVirtualMethodCall(self):
-        '''Test if a Python override of a reimplemented virtual method is correctly called from C++.'''
+        '''Test if a Python override of a reimplemented virtual method is
+           correctly called from C++.'''
         d = Deviant()
         d.callUnpureVirtual()
         self.assertTrue(d.unpure_virtual_called)
@@ -82,7 +96,8 @@ class DerivedTest(unittest.TestCase):
         self.assertEqual(d.getClassName(), 'Derived')
 
     def testReimplementedVirtualMethodCallReturningString(self):
-        '''Test if a Python override of a reimplemented virtual method is correctly called from C++.'''
+        '''Test if a Python override of a reimplemented virtual method is
+           correctly called from C++.'''
         d = Deviant()
         self.assertEqual(d.className(), 'Deviant')
         self.assertEqual(d.getClassName(), 'Deviant')
@@ -106,7 +121,8 @@ class DerivedTest(unittest.TestCase):
         self.assertEqual(Abstract.getObjectId(d), objId)
 
     def testObjectCreationWithParentType(self):
-        '''Derived class creates an instance of itself in C++ and returns it as a pointer to its ancestor Abstract.'''
+        '''Derived class creates an instance of itself in C++ and returns it as
+           a pointer to its ancestor Abstract.'''
         obj = Derived.createObject()
         self.assertEqual(type(obj), Derived)
 
@@ -115,7 +131,13 @@ class DerivedTest(unittest.TestCase):
         obj = DerivedUsingCt(42)
         self.assertEqual(obj.value(), 42)
 
+    def testVirtualWithOutParameter(self):
+        d = Derived()
+        self.assertEqual(d.callVirtualWithOutParameter(), 42)
+
+        d = ImplementVirtualWithOutParameter(1)
+        self.assertEqual(d.callVirtualWithOutParameter(), 1)
+
 
 if __name__ == '__main__':
     unittest.main()
-
index e1d89e2c0dab4ced979941af754cab09e903de2c..aa21a0f7ee677c84ec052ccad2c83e4ea5deb915 100644 (file)
@@ -16,6 +16,7 @@ init_paths()
 
 from sample import VirtualMethods, SimpleFile, Point
 
+
 def MethodTypeCompat(func, instance):
     return types.MethodType(func, instance)
 
@@ -24,10 +25,12 @@ class Duck(VirtualMethods):
     def __init__(self):
         VirtualMethods.__init__(self)
 
+
 class Monkey(SimpleFile):
     def __init__(self, filename):
         SimpleFile.__init__(self, filename)
 
+
 class DuckPunchingTest(unittest.TestCase):
     '''Test case for duck punching (aka "monkey patching").'''
 
@@ -56,7 +59,8 @@ class DuckPunchingTest(unittest.TestCase):
 
         result2 = vm.virtualMethod0(pt, val, cpx, b)
         self.assertEqual(result1, result2)
-        self.assertEqual(result1, VirtualMethods.virtualMethod0(vm, pt, val, cpx, b) * self.multiplier)
+        self.assertEqual(result1,
+                         VirtualMethods.virtualMethod0(vm, pt, val, cpx, b) * self.multiplier)
 
         # This is done to decrease the refcount of the vm object
         # allowing the object wrapper to be deleted before the
@@ -66,7 +70,8 @@ class DuckPunchingTest(unittest.TestCase):
         vm.virtualMethod0 = None
 
     def testMonkeyPatchOnVirtualMethodWithInheritance(self):
-        '''Injects new 'virtualMethod0' on an object that inherits from VirtualMethods and makes C++ call it.'''
+        '''Injects new 'virtualMethod0' on an object that inherits from
+           VirtualMethods and makes C++ call it.'''
         duck = Duck()
         pt, val, cpx, b = Point(1.1, 2.2), 4, complex(3.3, 4.4), True
 
@@ -85,7 +90,8 @@ class DuckPunchingTest(unittest.TestCase):
 
         result2 = duck.virtualMethod0(pt, val, cpx, b)
         self.assertEqual(result1, result2)
-        self.assertEqual(result1, VirtualMethods.virtualMethod0(duck, pt, val, cpx, b) * self.multiplier)
+        self.assertEqual(result1,
+                         VirtualMethods.virtualMethod0(duck, pt, val, cpx, b) * self.multiplier)
 
         duck.virtualMethod0 = None
 
@@ -150,4 +156,3 @@ class DuckPunchingTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 567d1452ac5e71e75bdf0cc8494dd140507f6eaf..f1859260ea3df9403123de33ae7f2c4c8ed73a45 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import Echo
 
+
 class TestEcho(unittest.TestCase):
     '''Simple test case for Echo.echo'''
 
@@ -26,7 +27,8 @@ class TestEcho(unittest.TestCase):
 
     def testCallOperator(self):
         e = Echo()
-        self.assertEqual(e("Hello", 3), "Hello3");
+        self.assertEqual(e("Hello", 3), "Hello3")
+
+
 if __name__ == '__main__':
     unittest.main()
-
index c140a12be6f375516a8f25a69b07259cd2c3dd98..276b8d8949483d97ccac4ff3d6f360cd39d9b346 100644 (file)
@@ -13,12 +13,10 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-import shiboken6
 # This is needed after the introduction of BUILD_DIR.
 
 import sample
 from sample import SampleNamespace, ObjectType, Event
-from shibokensupport.signature import get_signature
 
 
 def createTempFile():
@@ -69,8 +67,10 @@ class EnumTest(unittest.TestCase):
 
     def testEnumItemAsDefaultValueToIntArgument(self):
         '''Calls function with an enum item as default value to an int argument.'''
-        self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(), SampleNamespace.ZeroIn)
-        self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(SampleNamespace.ZeroOut), SampleNamespace.ZeroOut)
+        self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(),
+                         SampleNamespace.ZeroIn)
+        self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(SampleNamespace.ZeroOut),  # noqa E:501
+                         SampleNamespace.ZeroOut)
         self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(123), 123)
 
     def testAnonymousGlobalEnums(self):
@@ -101,7 +101,8 @@ class EnumTest(unittest.TestCase):
     def testEnumArgumentWithDefaultValue(self):
         '''Option enumArgumentWithDefaultValue(Option opt = UnixTime);'''
         self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(), SampleNamespace.UnixTime)
-        self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(SampleNamespace.RandomNumber), SampleNamespace.RandomNumber)
+        self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(SampleNamespace.RandomNumber),  # noqa E:501
+                         SampleNamespace.RandomNumber)
 
 
 class MyEvent(Event):
@@ -135,4 +136,3 @@ class EnumOperators(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 004caac708dd9374155636ebc95bf4d6bef16ddf..42ae23961da279b3a9f8cf09f956e88b162c3520 100644 (file)
@@ -14,8 +14,6 @@ init_paths()
 import sample
 from shiboken_test_helper import objectFullname
 
-from shiboken6 import Shiboken
-
 from shibokensupport.signature import get_signature
 
 
@@ -46,9 +44,8 @@ class TestEnumFromRemovedNamespace(unittest.TestCase):
         sample.UnremovedNamespace.RemovedNamespace3_AnonymousEnum_Value0
 
     def testNestedFunctionFromRemovedNamespace(self):
-            self.assertEqual(sample.UnremovedNamespace.nestedMathSum(1, 2), 3)
+        self.assertEqual(sample.UnremovedNamespace.nestedMathSum(1, 2), 3)
 
 
 if __name__ == '__main__':
     unittest.main()
-
index e61656400cde21df69b5a9caaf5e21caf7e258c4..8e13d5d46f05e644a6384354961bf75927a5ee22 100644 (file)
@@ -6,14 +6,12 @@
 
 import os
 import sys
-import time
 import unittest
 
 from pathlib import Path
 sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
-from random import random
 
 from sample import ObjectType, Event
 
@@ -41,7 +39,7 @@ class TestEventLoop(unittest.TestCase):
         objs = [ObjectType(), NoOverride(), Override()]
 
         evaluated = ObjectType.processEvent(objs,
-                                        Event(Event.BASIC_EVENT))
+                                            Event(Event.BASIC_EVENT))
 
         self.assertEqual(evaluated, 3)
         self.assertTrue(objs[2].called)
index 2cd1c8d0ad1a9882ac660156dfe0f99e997e2245..8b854fca6baf0a04f6725b5d3ee6ea314a3dd4b2 100644 (file)
@@ -64,7 +64,7 @@ class TestEventLoopWithThread(unittest.TestCase):
         thread.start()
 
         evaluated = ObjectType.processEvent(objs,
-                                        Event(Event.BASIC_EVENT))
+                                            Event(Event.BASIC_EVENT))
 
         thread.join()
 
index 78e583da0b027d5631ef29dd1fc17cd5bb6eec3c..d9e6b377f1ac37f4c8bfe4cd80b3143971b5853a 100644 (file)
@@ -13,6 +13,7 @@ init_paths()
 
 from sample import ExceptionTest
 
+
 class CppExceptionTest(unittest.TestCase):
 
     def testVoid(self):
@@ -23,14 +24,14 @@ class CppExceptionTest(unittest.TestCase):
 
         try:
             et.voidThrowStdException(True)
-        except:
+        except:  # noqa: E722
             exceptionCount += 1
 
         et.voidThrowInt(False)
 
         try:
             et.voidThrowInt(True)
-        except:
+        except:  # noqa: E722
             exceptionCount += 1
 
         self.assertEqual(exceptionCount, 2)
@@ -39,18 +40,18 @@ class CppExceptionTest(unittest.TestCase):
         exceptionCount = 0
         et = ExceptionTest()
 
-        result = et.intThrowStdException(False);
+        result = et.intThrowStdException(False)
 
         try:
-            result = et.intThrowStdException(True);
-        except:
+            result = et.intThrowStdException(True)
+        except:  # noqa: E722
             exceptionCount += 1
 
-        result = et.intThrowInt(False);
+        result = et.intThrowInt(False)
 
         try:
-            result = et.intThrowInt(True);
-        except:
+            result = et.intThrowInt(True)  # noqa: F841
+        except:  # noqa: E722
             exceptionCount += 1
 
         self.assertEqual(exceptionCount, 2)
@@ -60,8 +61,8 @@ class CppExceptionTest(unittest.TestCase):
                when return ownership modifications are generated."""
             exceptionCount = 0
             try:
-                et = ExceptionTest.create(True);
-            except:
+                et = ExceptionTest.create(True)  # noqa: F841
+            except:  # noqa: E722
                 exceptionCount += 1
             self.assertEqual(exceptionCount, 1)
 
index 86c5fba2a0f73c973ef26ff37a4068b8b5f8ecc2..df805093f54e3988ee292d47e5fe42db3c8e013b 100644 (file)
@@ -12,6 +12,7 @@ init_paths()
 
 from sample import Data, Intersection, Union
 
+
 class TestFilters(unittest.TestCase):
 
     def testAnd(self):
@@ -23,5 +24,6 @@ class TestFilters(unittest.TestCase):
 
         self.assertEqual(type(inter), Intersection)
 
+
 if __name__ == '__main__':
     unittest.main()
index 273915719d8ade0e730965983da9e45bb3fc6a0a..af22328c54e487f16b14ea966307712915123ddd 100644 (file)
@@ -17,6 +17,7 @@ init_paths()
 
 from sample import HandleHolder
 
+
 class HandleHolderTest(unittest.TestCase):
     def testCreation(self):
         holder = HandleHolder(HandleHolder.createHandle())
@@ -33,5 +34,6 @@ class HandleHolderTest(unittest.TestCase):
         holder2 = HandleHolder(holder.handle2())
         self.assertTrue(holder.compare2(holder2))
 
+
 if __name__ == '__main__':
     unittest.main()
index 20d3d2eddf56301b35e2817b6ec0338e5034c78e..c41f5cc066438eafac611141aebb3d85491a2698 100644 (file)
@@ -13,7 +13,8 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import ObjectType, Str
+
 
 class HashableTest(unittest.TestCase):
 
@@ -29,6 +30,6 @@ class HashableTest(unittest.TestCase):
         h[o] = 2
         self.assertTrue(h.get(o), 2)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 89df035a3573f5d0c62a28506f77570aef68b10d..feb78d04566872a77e2db35ca5e3772550c0d592 100644 (file)
@@ -9,12 +9,14 @@ from pathlib import Path
 sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
-from sample import *
+from sample import Reference
+
 
 class TestLackOfDereferenceOperators (unittest.TestCase):
     def testIf(self):
         r = Reference()
         self.assertFalse(hasattr(r, "__mul__"))
 
+
 if __name__ == '__main__':
     unittest.main()
index c5c7bc0d12783d79c56115a7fadc7ea342e02c96..0816662814cb5fe0c551e02976fc31603ce3ea4f 100644 (file)
@@ -27,6 +27,7 @@ if is64bitArchitecture and sys.platform != 'win32':
     cLongMin = -9223372036854775808
     cLongMax = 9223372036854775807
 
+
 class NumericTester(unittest.TestCase):
     '''Helper class for numeric comparison testing'''
 
index 96cad9c69a81c9dbe0fd75f4283b61d5e88bd537..ebafe0c5273ace81db9b64857f7e636bd7408e06 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import ImplicitConv, ObjectType
 
+
 class ImplicitConvTest(unittest.TestCase):
     '''Test case for implicit conversions'''
 
@@ -43,4 +44,3 @@ class ImplicitConvTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 7ae6761025cbaedde908a1e7c591cd0af7be0e96..28d62486adcd85349ea66746d49e1ed752e3b423 100644 (file)
@@ -15,14 +15,16 @@ init_paths()
 
 from sample import SampleNamespace
 
+
 class ScopeAndInheritanceTest(unittest.TestCase):
     '''Test cases for finding scope in cases involving inheritance.'''
 
     def testMethodCorrectlyWrapper(self):
         '''A method returning a type declared in the scope of the method's
         class parent must be found and the method correctly exported.'''
-        meth = getattr(SampleNamespace.DerivedFromNamespace, 'methodReturningTypeFromParentScope')
+        meth = getattr(SampleNamespace.DerivedFromNamespace,  # noqa: F841
+                       'methodReturningTypeFromParentScope')
+
 
 if __name__ == '__main__':
     unittest.main()
-
index 90225a039b040db643af5819b5bba38dc117f89b..f673a7807d24e22f839ff1d73fd76eba0d67de6e 100644 (file)
@@ -14,6 +14,7 @@ from shiboken_paths import init_paths
 init_paths()
 from sample import InjectCode
 
+
 class MyInjectCode(InjectCode):
     def __init__(self):
         InjectCode.__init__(self)
@@ -22,10 +23,11 @@ class MyInjectCode(InjectCode):
     def arrayMethod(self, values):
         return self.multiplier * sum(values)
 
+
 class InjectCodeTest(unittest.TestCase):
 
     @unittest.skipIf(hasattr(sys, "pypy_version_info"),
-                             "PyPy type objects cannot be modified (yet) after creation")
+                     "PyPy type objects cannot be modified (yet) after creation")
     def testTypeNativeBeginning_TypeTargetBeginning(self):
         ic = InjectCode()
         self.assertEqual(str(ic), "Hi! I'm the inject code dummy class.")
@@ -71,22 +73,24 @@ class InjectCodeTest(unittest.TestCase):
         self.assertEqual(result, sum(values))
 
     def testCallReimplementedVirtualMethodWithArgumentRemovalAndArgumentTypeModification(self):
-        '''Calls a reimplemented virtual method that had its first argument removed and the second modified.'''
+        '''Calls a reimplemented virtual method that had its first argument removed
+           and the second modified.'''
         ic = MyInjectCode()
         values = (1, 2, 3, 4, 5)
         result = ic.callArrayMethod(values)
         self.assertEqual(result, ic.multiplier * sum(values))
 
     def testUsageOfTypeSystemCheckVariableOnPrimitiveType(self):
-        '''When the sequence item is convertible to an integer -1 is returned, or -2 if its not convertible.'''
+        '''When the sequence item is convertible to an integer -1 is returned,
+           or -2 if its not convertible.'''
         ic = InjectCode()
         values = (1, 2, 3, 4, '5', 6.7)
         result = ic.arrayMethod(values)
 
-        fixedValues = [v for v in values if isinstance(v, int)]\
-                    + [-1 for v in values if isinstance(v, float)]\
-                    + [-2 for v in values if not isinstance(v, int) and not isinstance(v, float)]
-        self.assertEqual(result, sum(fixedValues))
+        ints = [v for v in values if isinstance(v, int)]
+        floats = [-1 for v in values if isinstance(v, float)]
+        other = [-2 for v in values if not isinstance(v, int) and not isinstance(v, float)]
+        self.assertEqual(result, sum(ints + floats + other))
 
 
 class IntArrayTest(unittest.TestCase):
@@ -110,5 +114,6 @@ class IntArrayTest(unittest.TestCase):
         ic = InjectCode()
         self.assertEqual(sum([1, 2]) + len([1, 2]), ic.sumArrayAndLength(args))
 
+
 if __name__ == '__main__':
     unittest.main()
index f94c577503cd5ec685ae6b544f48f63ab6c6f87f..721f33483dc6117a41ca177de4e1a88490ac4e77 100644 (file)
@@ -13,10 +13,11 @@ init_paths()
 
 from sample import Derived
 
+
 class TestInnerClass(unittest.TestCase):
     def testInstaciate(self):
-        d = Derived.SomeInnerClass()
+        d = Derived.SomeInnerClass()  # noqa: F841
+
 
 if __name__ == '__main__':
     unittest.main()
-
index 41d2b659a0f613ee83e2c8e3c84fae172f80f974..defa9ca713953db40506a2fc880d8eba2ec3c1f7 100644 (file)
@@ -13,6 +13,7 @@ init_paths()
 
 from sample import IntList
 
+
 class IntListTest(unittest.TestCase):
 
     def testAutoFunctionsToBaseList(self):
@@ -74,5 +75,6 @@ class IntListTest(unittest.TestCase):
         self.assertEqual(il[1], int(432.1))
         self.assertRaises(TypeError, il.__setitem__, 2, '78')
 
+
 if __name__ == '__main__':
     unittest.main()
index 21cab6b3541eed3d1ecff86392f490b7f633584d..d883adf4708cc8d9ac6bb766150a24e0b37fd8ed 100644 (file)
@@ -16,8 +16,8 @@ from sample import IntWrapper
 class IntWrapperTest(unittest.TestCase):
 
     def testOperators(self):
-        ten1  = IntWrapper(10)
-        ten2  = IntWrapper(10)
+        ten1 = IntWrapper(10)
+        ten2 = IntWrapper(10)
         twenty = IntWrapper(20)
         self.assertTrue(ten1 == ten2)
         self.assertTrue(ten1 != twenty)
index e3d0604302aa6f5f7a1331249f46294a25b03f4a..bb35b2bb1f99a0a0aefa5d2cd6bf03b2f1144592 100644 (file)
@@ -38,7 +38,7 @@ class ModelWrongReturnTest(unittest.TestCase):
     def testWrongTypeReturn(self):
         model = ListModelWrong()
         view = ObjectView(model)
-        self.assertRaises(RuntimeWarning, view.getRawModelData) # calls model.data()
+        self.assertRaises(RuntimeWarning, view.getRawModelData)  # calls model.data()
 
 
 if __name__ == '__main__':
index 6cf416fc40849a8cda7bb6ab3c45bd5b157142db..10591fec6c1035526de341acba080f1751b7a253 100644 (file)
@@ -2,8 +2,6 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
-'''Test case for objects that keep references to other object without owning them (e.g. model/view relationships).'''
-
 import os
 import sys
 import unittest
@@ -15,8 +13,10 @@ init_paths()
 
 from sample import ObjectModel, ObjectView
 
+
 class TestKeepReference(unittest.TestCase):
-    '''Test case for objects that keep references to other object without owning them (e.g. model/view relationships).'''
+    '''Test case for objects that keep references to other object without
+       owning them (e.g. model/view relationships).'''
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testReferenceCounting(self):
@@ -48,15 +48,16 @@ class TestKeepReference(unittest.TestCase):
         self.assertEqual(sys.getrefcount(model), refcount1)
 
     def testReferreedObjectSurvivalAfterContextEnd(self):
-        '''Model-like object assigned to a view-like object must survive after get out of context.'''
+        '''Model-like object assigned to a view-like object must survive
+           after get out of context.'''
         def createModelAndSetToView(view):
             model = ObjectModel()
             model.setObjectName('created model')
             view.setModel(model)
         view = ObjectView()
         createModelAndSetToView(view)
-        model = view.model()
+        model = view.model()    # noqa: F841
+
 
 if __name__ == '__main__':
     unittest.main()
-
index 6eb975b9fe997d2ac2fae26cf0cd3b749d44e7fd..b668bfd90c896172372193a0d86d3b82fa24fa15 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import ListUser, Point, PointF
 
+
 class ExtendedListUser(ListUser):
     def __init__(self):
         ListUser.__init__(self)
@@ -24,6 +25,7 @@ class ExtendedListUser(ListUser):
         self.create_list_called = True
         return [2, 3, 5, 7, 13]
 
+
 class ListConversionTest(unittest.TestCase):
     '''Test case for std::list container conversions'''
 
@@ -69,7 +71,8 @@ class ListConversionTest(unittest.TestCase):
         self.assertEqual(result, lst)
 
     def testConversionInBothDirectionsWithSimilarContainer(self):
-        '''Test converting a tuple, instead of the expected list, from Python to C++ and back again.'''
+        '''Test converting a tuple, instead of the expected list,
+           from Python to C++ and back again.'''
         lu = ListUser()
         lst = (3, 5, 7)
         lu.setList(lst)
@@ -96,6 +99,6 @@ class ListConversionTest(unittest.TestCase):
         self.assertEqual(ListUser.ListOfPointF, ListUser.listOfPoints([PointF()]))
         self.assertEqual(ListUser.ListOfPoint, ListUser.listOfPoints([Point()]))
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 0657d41b9309587a7964130cdc7bec7d50069ffe..acd47634a1dc408221f2a26279feafefcd7179b7 100644 (file)
@@ -63,7 +63,8 @@ class TestLockUnlock(unittest.TestCase):
         self.assertTrue(result)
 
     def testReimplementedVirtualBlocker(self):
-        '''Same as the basic case but blocker method is a C++ virtual reimplemented in Python and called from C++.'''
+        '''Same as the basic case but blocker method is a C++ virtual reimplemented
+           in Python and called from C++.'''
         mybucket = MyBucket()
         unlocker = Unlocker(mybucket)
 
@@ -72,5 +73,6 @@ class TestLockUnlock(unittest.TestCase):
         unlocker.join()
         self.assertTrue(result)
 
+
 if __name__ == '__main__':
     unittest.main()
index 5ffed5ede10d8944724e64a5181aea39a044bc80..fa99ad2e7308e4d4747d6ce6a2171300baa201df 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import MapUser
 
+
 class ExtendedMapUser(MapUser):
     def __init__(self):
         MapUser.__init__(self)
@@ -22,10 +23,11 @@ class ExtendedMapUser(MapUser):
 
     def createMap(self):
         self.create_map_called = True
-        return {'two' : (complex(2.2, 2.2), 2),
-                'three' : (complex(3.3, 3.3), 3),
-                'five' : (complex(5.5, 5.5), 5),
-                'seven' : (complex(7.7, 7.7), 7)}
+        return {'two': (complex(2.2, 2.2), 2),
+                'three': (complex(3.3, 3.3), 3),
+                'five': (complex(5.5, 5.5), 5),
+                'seven': (complex(7.7, 7.7), 7)}
+
 
 class MapConversionTest(unittest.TestCase):
     '''Test case for std::map container conversions'''
@@ -44,7 +46,7 @@ class MapConversionTest(unittest.TestCase):
     def testConversionInBothDirections(self):
         '''Test converting a map from Python to C++ and back again.'''
         mu = MapUser()
-        map_ = {'odds' : [2, 4, 6], 'evens' : [3, 5, 7], 'primes' : [3, 4, 6]}
+        map_ = {'odds': [2, 4, 6], 'evens': [3, 5, 7], 'primes': [3, 4, 6]}
         mu.setMap(map_)
         result = mu.getMap()
         self.assertEqual(result, map_)
@@ -52,9 +54,10 @@ class MapConversionTest(unittest.TestCase):
     def testConversionMapIntKeyValueTypeValue(self):
         '''C++ signature: MapUser::passMapIntValueType(const std::map<int, const ByteArray>&)'''
         mu = MapUser()
-        map_ = {0 : 'string'}
+        map_ = {0: 'string'}
         result = mu.passMapIntValueType(map_)
         self.assertEqual(map_, result)
 
+
 if __name__ == '__main__':
     unittest.main()
index 787bace70dbb6d738f08ef7d52334cb0e440c098..4d7eeda963985b9c4a18f35d087065f3d3b2a78f 100644 (file)
@@ -10,32 +10,40 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import Point
+
 
 class MetaA(type):
     pass
 
+
 class A(object):
     __metaclass__ = MetaA
 
+
 MetaB = type(Point)
 B = Point
 
+
 class MetaC(MetaA, MetaB):
     pass
+
+
 class C(A, B):
     __metaclass__ = MetaC
 
+
 class D(C):
     pass
 
+
 class TestMetaClass(unittest.TestCase):
     def testIt(self):
-        w1 = C() # works
+        w1 = C()  # works
         w1.setX(1)
         w1.setY(2)
 
-        w2 = D() # should work!
+        w2 = D()  # should work!
         w2.setX(3)
         w2.setY(4)
 
index 776605a4dc2cdf197b093d9fba60e8d8a3912d3e..fa848160052444e85bc5df3808541cf8d776335d 100644 (file)
@@ -52,5 +52,3 @@ class MixedInheritanceTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
-
index 725105a9c8f64f327899f0d88b72c35b9e750a1b..e23503effde2fd10f2445eb4e51c92a74ca1a085 100644 (file)
@@ -13,6 +13,7 @@ init_paths()
 
 from sample import ModelIndex, ReferentModelIndex, PersistentModelIndex
 
+
 class TestCastOperator(unittest.TestCase):
 
     def testCastOperatorReturningValue(self):
@@ -30,4 +31,3 @@ class TestCastOperator(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 0b5c657d9715a48d42799efc23d31cfd0d7ca845..b5663a04e95ee36d74be202add154b8bfc9e21fc 100644 (file)
@@ -2,7 +2,8 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
-'''Test case for objects that keep references to other object without owning them (e.g. model/view relationships).'''
+'''Test case for objects that keep references to other object without owning them
+   (e.g. model/view relationships).'''
 
 import os
 import sys
@@ -17,9 +18,11 @@ from sample import ObjectModel, ObjectType, ObjectView
 
 object_name = 'test object'
 
+
 class MyObject(ObjectType):
     pass
 
+
 class ListModelKeepsReference(ObjectModel):
     def __init__(self, parent=None):
         ObjectModel.__init__(self, parent)
@@ -29,6 +32,7 @@ class ListModelKeepsReference(ObjectModel):
     def data(self):
         return self.obj
 
+
 class ListModelDoesntKeepsReference(ObjectModel):
     def data(self):
         obj = MyObject()
@@ -55,4 +59,3 @@ class ModelViewTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 0082215273b873e3123e49efbde03090537ffb3c..dced14396cb69f1abbad3e115bf0de9f94ef1ec3 100644 (file)
@@ -16,6 +16,7 @@ init_paths()
 
 from sample import Modifications, Point, ByteArray
 
+
 class ExtModifications(Modifications):
     def __init__(self):
         Modifications.__init__(self)
@@ -42,12 +43,14 @@ class ModificationsTest(unittest.TestCase):
         gc.collect()
 
     def testRenamedMethodAvailability(self):
-        '''Test if Modification class really have renamed the 'className' virtual method to 'name'.'''
+        '''Test if Modification class really have renamed the 'className'
+           virtual method to 'name'.'''
         self.assertTrue('className' not in dir(Modifications))
         self.assertTrue('name' in dir(Modifications))
 
     def testReimplementationOfRenamedVirtualMethod(self):
-        '''Test if class inheriting from Modification class have the reimplementation of renamed virtual method called.'''
+        '''Test if class inheriting from Modification class have the reimplementation
+           of renamed virtual method called.'''
         em = ExtModifications()
         self.assertEqual(self.mods.name(), 'Modifications')
         self.assertEqual(em.name(), 'ExtModifications')
@@ -68,12 +71,14 @@ class ModificationsTest(unittest.TestCase):
         self.assertEqual(self.mods.doublePlus(7), 14)
 
     def testDefaultValueRemoval(self):
-        '''Test if default value was removed from first argument of Modifications::increment(int).'''
+        '''Test if default value was removed from first argument of
+           Modifications::increment(int).'''
         self.assertRaises(TypeError, self.mods.increment)
         self.assertEqual(self.mods.increment(7), 8)
 
     def testDefaultValueReplacement(self):
-        '''Test if default values for both arguments of Modifications::power(int, int) were modified.'''
+        '''Test if default values for both arguments of Modifications::power(int, int)
+           were modified.'''
         # original default values: int power(int base = 1, int exponent = 0);
         self.assertNotEqual(self.mods.power(4), 1)
         # modified default values: int power(int base = 2, int exponent = 1);
@@ -82,12 +87,14 @@ class ModificationsTest(unittest.TestCase):
         self.assertEqual(self.mods.power(5, 3), 5**3)
 
     def testSetNewDefaultValue(self):
-        '''Test if default value was correctly set to 10 for first argument of Modifications::timesTen(int).'''
+        '''Test if default value was correctly set to 10 for first argument of
+           Modifications::timesTen(int).'''
         self.assertEqual(self.mods.timesTen(7), 70)
         self.assertEqual(self.mods.timesTen(), 100)
 
     def testArgumentRemovalAndReturnTypeModificationWithTypesystemTemplates1(self):
-        '''Test modifications to method signature and return value using type system templates (case 1).'''
+        '''Test modifications to method signature and return value using type
+           system templates (case 1).'''
         result, ok = self.mods.pointToPair(Point(2, 5))
         self.assertEqual(type(ok), bool)
         self.assertEqual(type(result), tuple)
@@ -98,7 +105,8 @@ class ModificationsTest(unittest.TestCase):
         self.assertEqual(result[1], 5.0)
 
     def testArgumentRemovalAndReturnTypeModificationWithTypesystemTemplates2(self):
-        '''Test modifications to method signature and return value using type system templates (case 2).'''
+        '''Test modifications to method signature and return value using
+           type system templates (case 2).'''
         result, ok = self.mods.multiplyPointCoordsPlusValue(Point(2, 5), 4.1)
         self.assertEqual(type(ok), bool)
         self.assertEqual(type(result), float)
@@ -112,9 +120,11 @@ class ModificationsTest(unittest.TestCase):
         self.assertEqual(self.mods.overloaded(1, True, 2), Modifications.Overloaded_ibii)
         # the others weren't modified
         self.assertEqual(self.mods.overloaded(1, True, 2, False), Modifications.Overloaded_ibib)
-        self.assertEqual(self.mods.overloaded(1, False, 2, Point(3, 4)), Modifications.Overloaded_ibiP)
+        self.assertEqual(self.mods.overloaded(1, False, 2, Point(3, 4)),
+                         Modifications.Overloaded_ibiP)
         self.assertRaises(TypeError, self.mods.overloaded, 1, True, Point(2, 3), Point(4, 5))
-        self.assertEqual(self.mods.over(1, True, Point(2, 3), Point(4, 5)), Modifications.Overloaded_ibPP)
+        self.assertEqual(self.mods.over(1, True, Point(2, 3), Point(4, 5)),
+                         Modifications.Overloaded_ibPP)
 
     def testPointArrayModification(self):
         points = (Point(1, 1), Point(2, 2))
index d4b65a88a380b2cfb46ac1e06fb7bb1e49760047..9791a34919cfafad46662f0105c5ab5afeb2a505 100644 (file)
@@ -4,7 +4,6 @@
 
 '''Tests cases for ConstructorWithModifiedArgument class.'''
 
-import sys
 import os
 import sys
 import unittest
@@ -14,7 +13,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import ModifiedConstructor
 
 
 class ConstructorWithModifiedArgumentTest(unittest.TestCase):
@@ -24,6 +23,6 @@ class ConstructorWithModifiedArgumentTest(unittest.TestCase):
         sampleClass = ModifiedConstructor("10")
         self.assertTrue(sampleClass.retrieveValue(), 10)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index ae090f8e36ecc42e1eccc152b7ece0b0a77c40e8..dcb487f1a664cdd15d5679f898e44678f9973a04 100644 (file)
@@ -16,6 +16,7 @@ init_paths()
 
 from sample import VirtualMethods, Str
 
+
 class ExtendedVirtualMethods(VirtualMethods):
     def __init__(self):
         VirtualMethods.__init__(self)
@@ -61,7 +62,7 @@ class ExtendedVirtualMethods(VirtualMethods):
         self.callMe_called += 1
 
     def getMargins(self):
-        return tuple([m*2 for m in VirtualMethods.getMargins(self)])
+        return tuple([m * 2 for m in VirtualMethods.getMargins(self)])
 
 
 class VirtualMethodsTest(unittest.TestCase):
@@ -185,7 +186,8 @@ class VirtualMethodsTest(unittest.TestCase):
         removed_arg_value = 2011
         default_value = 3000
         result = self.evm.callSum4(a0, removed_arg_value, a1)
-        self.assertEqual(result, (a0 - removed_arg_value + a1 + default_value) * self.evm.multiplier)
+        self.assertEqual(result,
+                         (a0 - removed_arg_value + a1 + default_value) * self.evm.multiplier)
         self.assertTrue(self.evm.sum4_called)
 
     def testOverridenMethodResultModification(self):
@@ -217,15 +219,15 @@ class VirtualMethodsTest(unittest.TestCase):
     def testExtendedAllArgumentsRemoved(self):
         values = (10, 20, 30, 40)
         self.evm.setMargins(*values)
-        double = tuple([m*2 for m in values])
+        double = tuple([m * 2 for m in values])
         self.assertEqual(self.evm.getMargins(), double)
 
     def testExtendedAllArgumentsRemovedCallVirtual(self):
         values = (10, 20, 30, 40)
         self.evm.setMargins(*values)
-        double = tuple([m*2 for m in values])
+        double = tuple([m * 2 for m in values])
         self.assertEqual(self.evm.callGetMargins(), double)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 6fd73537942b967afdb877bcd9c45e05840d137b..fc6b26c3f09dd9fdb2f682a17368ac67b88ae7ef 100644 (file)
@@ -13,77 +13,85 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import ObjectType, Point, Str
+
 
 class SimpleUseCase(ObjectType, Str):
     def __init__(self, name):
         ObjectType.__init__(self)
         Str.__init__(self, name)
 
+
 class SimpleUseCaseReverse(Str, ObjectType):
     def __init__(self, name):
         ObjectType.__init__(self)
         Str.__init__(self, name)
 
+
 class SimpleUseCase2(SimpleUseCase):
     def __init__(self, name):
         SimpleUseCase.__init__(self, name)
 
+
 class ComplexUseCase(SimpleUseCase2, Point):
     def __init__(self, name):
         SimpleUseCase2.__init__(self, name)
         Point.__init__(self)
 
+
 class ComplexUseCaseReverse(Point, SimpleUseCase2):
     def __init__(self, name):
         SimpleUseCase2.__init__(self, name)
         Point.__init__(self)
 
+
 class MultipleCppDerivedTest(unittest.TestCase):
-    def testInstanciation(self):
+    def testInstantiation(self):
         s = SimpleUseCase("Hi")
         self.assertEqual(s, "Hi")
         s.setObjectName(s)
         self.assertEqual(s.objectName(), "Hi")
 
-    def testInstanciation2(self):
+    def testInstantiation2(self):
         s = SimpleUseCase2("Hi")
         self.assertEqual(s, "Hi")
         s.setObjectName(s)
         self.assertEqual(s.objectName(), "Hi")
 
-    def testComplexInstanciation(self):
+    def testComplexInstantiation(self):
         c = ComplexUseCase("Hi")
         self.assertEqual(c, "Hi")
         c.setObjectName(c)
         self.assertEqual(c.objectName(), "Hi")
-        c.setX(2);
+        c.setX(2)
         self.assertEqual(c.x(), 2)
 
+
 class MultipleCppDerivedReverseTest(unittest.TestCase):
-    def testInstanciation(self):
+    def testInstantiation(self):
         s = SimpleUseCaseReverse("Hi")
         self.assertEqual(s, "Hi")
         s.setObjectName(s)
         self.assertEqual(s.objectName(), "Hi")
 
-    def testInstanciation2(self):
+    def testInstantiation2(self):
         s = SimpleUseCase2("Hi")
         self.assertEqual(s, "Hi")
         s.setObjectName(s)
         self.assertEqual(s.objectName(), "Hi")
 
-    def testComplexInstanciation(self):
+    def testComplexInstantiation(self):
         # PYSIDE-1564: This test can no longer work because of this MRO:
         # ('ComplexUseCaseReverse', 'Point', 'SimpleUseCase2', 'SimpleUseCase',
         #  'ObjectType', 'Str', 'Object', 'object')
         # By multiple inheritance Point would be called first but has no argument.
         with self.assertRaises(TypeError):
-            c = ComplexUseCaseReverse("Hi")
+            c = ComplexUseCaseReverse("Hi")  # noqa: F841
         # c.setObjectName(c)
         # self.assertEqual(c.objectName(), "Hi")
         # c.setX(2);
         # self.assertEqual(c, Point(2, 0))
 
+
 if __name__ == '__main__':
     unittest.main()
index 46e44601d0edf2b9ee552d7a217b558a6d97adc5..7497714a821c0d449cf108e66fbbfdca31812b61 100644 (file)
@@ -13,17 +13,20 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import Base1, Base2, Base3, Base4, Base5, Base6
+from sample import Base1, Base2
 from sample import MDerived1, MDerived2, MDerived3, MDerived4, MDerived5, SonOfMDerived1
 
+
 class ExtMDerived1(MDerived1):
     def __init__(self):
         MDerived1.__init__(self)
         self.multiplier = 20
         self.base2Method_called = False
+
     def base2Method(self):
         return Base2.base2Method(self) * self.multiplier
 
+
 class MultipleDerivedTest(unittest.TestCase):
     '''Test cases for multiple inheritance'''
 
@@ -40,19 +43,22 @@ class MultipleDerivedTest(unittest.TestCase):
         self.assertTrue(issubclass(MDerived1, Base2))
 
     def testCallToFunctionWithBase1ArgumentThatCastsBackToMDerived1(self):
-        '''MDerived1 is passed as an Base1 argument to a method that returns it casted back to MDerived1.'''
+        '''MDerived1 is passed as an Base1 argument to a method that returns
+           it casted back to MDerived1.'''
         a = MDerived1()
         b = MDerived1.transformFromBase1(a)
         self.assertEqual(a, b)
 
     def testCallToFunctionWithBase2ArgumentThatCastsBackToMDerived1(self):
-        '''MDerived1 is passed as an Base2 argument to a method that returns it casted back to MDerived1.'''
+        '''MDerived1 is passed as an Base2 argument to a method that returns
+           it casted back to MDerived1.'''
         a = MDerived1()
         b = MDerived1.transformFromBase2(a)
         self.assertEqual(a, b)
 
     def testPythonClassIsInstance(self):
-        '''Python defined class ExtMDerived1 is instance of its parents MDerived1, Base1 and Base2.'''
+        '''Python defined class ExtMDerived1 is instance of its parents
+           MDerived1, Base1 and Base2.'''
         a = ExtMDerived1()
         self.assertTrue(isinstance(a, ExtMDerived1))
         self.assertTrue(isinstance(a, MDerived1))
@@ -60,14 +66,16 @@ class MultipleDerivedTest(unittest.TestCase):
         self.assertTrue(isinstance(a, Base2))
 
     def testPythonClassIsSubclass(self):
-        '''Python defined class ExtMDerived1 is subclass of its parents MDerived1, Base1 and Base2.'''
+        '''Python defined class ExtMDerived1 is subclass of its parents
+           MDerived1, Base1 and Base2.'''
         self.assertTrue(issubclass(ExtMDerived1, MDerived1))
         self.assertTrue(issubclass(ExtMDerived1, Base1))
         self.assertTrue(issubclass(ExtMDerived1, Base2))
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testCastFromMDerived1ToBases(self):
-        '''MDerived1 is casted by C++ to its parents and the binding must return the MDerived1 wrapper.'''
+        '''MDerived1 is casted by C++ to its parents and the binding must return the
+           MDerived1 wrapper.'''
         a = MDerived1()
         refcnt = sys.getrefcount(a)
         b1 = a.castToBase1()
@@ -80,7 +88,8 @@ class MultipleDerivedTest(unittest.TestCase):
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testCastFromExtMDerived1ToMDerived1Bases(self):
-        '''Python defined class ExtMDerived1 is casted by C++ to MDerived1 parents and the binding must return the correct ExtMDerived1 instance.'''
+        '''Python defined class ExtMDerived1 is casted by C++ to MDerived1 parents
+           and the binding must return the correct ExtMDerived1 instance.'''
         a = ExtMDerived1()
         refcnt = sys.getrefcount(a)
         b1 = a.castToBase1()
@@ -95,7 +104,8 @@ class MultipleDerivedTest(unittest.TestCase):
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testCastFromSonOfMDerived1ToBases(self):
-        '''SonOfMDerived1 is casted by C++ to its parents and the binding must return the SonOfMDerived1 wrapper.'''
+        '''SonOfMDerived1 is casted by C++ to its parents and the binding must return
+           the SonOfMDerived1 wrapper.'''
         a = SonOfMDerived1()
         refcnt = sys.getrefcount(a)
         md1 = a.castToMDerived1()
@@ -116,7 +126,8 @@ class MultipleDerivedTest(unittest.TestCase):
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testCastFromMDerived2ToBases(self):
-        '''MDerived2 is casted by C++ to its parents and the binding must return the MDerived2 wrapper.'''
+        '''MDerived2 is casted by C++ to its parents and the binding must
+           return the MDerived2 wrapper.'''
         a = MDerived2()
         refcnt = sys.getrefcount(a)
         b3 = a.castToBase3()
@@ -135,7 +146,8 @@ class MultipleDerivedTest(unittest.TestCase):
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testCastFromMDerived3ToBases(self):
-        '''MDerived3 is casted by C++ to its parents and the binding must return the MDerived3 wrapper.'''
+        '''MDerived3 is casted by C++ to its parents and the binding must
+           return the MDerived3 wrapper.'''
         a = MDerived3()
         refcnt = sys.getrefcount(a)
         md1 = a.castToMDerived1()
@@ -166,7 +178,8 @@ class MultipleDerivedTest(unittest.TestCase):
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testCastFromMDerived4ToBases(self):
-        '''MDerived4 is casted by C++ to its parents and the binding must return the MDerived4 wrapper.'''
+        '''MDerived4 is casted by C++ to its parents and the binding must
+           return the MDerived4 wrapper.'''
         a = MDerived4()
         refcnt = sys.getrefcount(a)
         b3 = a.castToBase3()
@@ -179,7 +192,8 @@ class MultipleDerivedTest(unittest.TestCase):
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testCastFromMDerived5ToBases(self):
-        '''MDerived5 is casted by C++ to its parents and the binding must return the MDerived5 wrapper.'''
+        '''MDerived5 is casted by C++ to its parents and the binding must
+           return the MDerived5 wrapper.'''
         a = MDerived5()
         refcnt = sys.getrefcount(a)
         b3 = a.castToBase3()
@@ -192,7 +206,8 @@ class MultipleDerivedTest(unittest.TestCase):
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testCastFromMDerived3ToBase3(self):
-        '''MDerived3 is casted by C++ to Base3 grandparent using both the inherited and reimplement castToBase3 methods.'''
+        '''MDerived3 is casted by C++ to Base3 grandparent using both the inherited
+           and reimplement castToBase3 methods.'''
         a = MDerived3()
         refcnt = sys.getrefcount(a)
         b3_reimplemented = a.castToBase3()
@@ -203,6 +218,6 @@ class MultipleDerivedTest(unittest.TestCase):
         self.assertEqual(a, b3_inherited)
         self.assertEqual(sys.getrefcount(a), refcnt + 2)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 9740a137d31258c98206cd0cd21324fcc48c7a5f..64a6792ac5473cc1f893005d7398237e13b64170 100644 (file)
@@ -13,11 +13,9 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import SampleNamespace
 from shiboken_test_helper import objectFullname
 
-from shiboken6 import Shiboken
-
 from shibokensupport.signature import get_signature
 
 # For tests of invisible namespaces, see
@@ -26,17 +24,17 @@ from shibokensupport.signature import get_signature
 
 class TestVariablesUnderNamespace(unittest.TestCase):
     def testIt(self):
-         self.assertEqual(SampleNamespace.variableInNamespace, 42)
+        self.assertEqual(SampleNamespace.variableInNamespace, 42)
 
 
 class TestClassesUnderNamespace(unittest.TestCase):
     def testIt(self):
-        c1 = SampleNamespace.SomeClass()
-        e1 = SampleNamespace.SomeClass.ProtectedEnum()
-        c2 = SampleNamespace.SomeClass.SomeInnerClass()
-        e2 = SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum()
-        c3 = SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough()
-        e3 = SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum(0)
+        c1 = SampleNamespace.SomeClass()  # noqa F841
+        e1 = SampleNamespace.SomeClass.ProtectedEnum()  # noqa F841
+        c2 = SampleNamespace.SomeClass.SomeInnerClass()  # noqa F841
+        e2 = SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum()  # noqa F841
+        c3 = SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough()  # noqa F841
+        e3 = SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum(0)  # noqa F841
 
     def testFunctionAddedOnNamespace(self):
         res = SampleNamespace.ImInsideANamespace(2, 2)
@@ -44,22 +42,21 @@ class TestClassesUnderNamespace(unittest.TestCase):
 
     def testTpNames(self):
         self.assertEqual(str(SampleNamespace.SomeClass),
-            "<class 'sample.SampleNamespace.SomeClass'>")
+                         "<class 'sample.SampleNamespace.SomeClass'>")
         self.assertEqual(str(SampleNamespace.SomeClass.ProtectedEnum),
-            "<enum 'ProtectedEnum'>")
+                         "<enum 'ProtectedEnum'>")
         self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum),
-            "<enum 'ProtectedEnum'>")
+                         "<enum 'ProtectedEnum'>")
         self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough),
-            "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>")
-        self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum),
-            "<enum 'NiceEnum'>")
+                         "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>")  # noqa: E501
+        self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum),  # noqa: E501
+                         "<enum 'NiceEnum'>")
 
         # Test if enum inside of class is correct represented
-        self.assertEqual(objectFullname(get_signature(SampleNamespace.enumInEnumOut).parameters['in_'].annotation),
-            "sample.SampleNamespace.InValue")
-        self.assertEqual(objectFullname(get_signature(SampleNamespace.enumAsInt).parameters['value'].annotation),
-            "sample.SampleNamespace.SomeClass.PublicScopedEnum")
-
+        an = objectFullname(get_signature(SampleNamespace.enumInEnumOut).parameters['in_'].annotation)  # noqa: E501
+        self.assertEqual(an, "sample.SampleNamespace.InValue")
+        an = objectFullname(get_signature(SampleNamespace.enumAsInt).parameters['value'].annotation)
+        self.assertEqual(an, "sample.SampleNamespace.SomeClass.PublicScopedEnum")
 
     def testInlineNamespaces(self):
         cls = SampleNamespace.ClassWithinInlineNamespace()
index 6286dcfc9472e842d29e735fc860f1c307091bce..0e7dfbee19a6f3d44191a7750f4a475cfb7a4368 100644 (file)
@@ -10,16 +10,16 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import Point
 
 
 class TestNewDivision(unittest.TestCase):
 
     def testIt(self):
         p = Point(4, 4)
-        p2 = p/2
+        p2 = p / 2
         self.assertEqual(p2, Point(2, 2))
 
+
 if __name__ == "__main__":
     unittest.main()
-
index 3892508aec6ee69b09bea0815d1f4caacb6775be..bc8d29e500ee938163f9bb180c98cf360175f3e0 100644 (file)
@@ -15,14 +15,17 @@ init_paths()
 
 from sample import NonDefaultCtor
 
+
 class DerivedNonDefaultCtor (NonDefaultCtor):
     def returnMyselfVirtual(self):
-        return NonDefaultCtor(self.value()+1)
+        return NonDefaultCtor(self.value() + 1)
+
 
 class AnotherDerivedNonDefaultCtor (NonDefaultCtor):
     def __init__(self, some_string):
         pass
 
+
 class NonDefaultCtorTest(unittest.TestCase):
 
     def testNonDefaultCtor(self):
@@ -43,8 +46,8 @@ class NonDefaultCtorTest(unittest.TestCase):
         self.assertEqual(c.callReturnMyselfVirtual().value(), 4)
 
     def testCtorOverload(self):
-        c = AnotherDerivedNonDefaultCtor("testing")
+        c = AnotherDerivedNonDefaultCtor("testing")  # noqa: F841
+
 
 if __name__ == '__main__':
     unittest.main()
-
index fa28abc6d5862f5fa8fccd7a477ccdaa3c3159ca..a10547728e229f36993ccaa5ba316999a0630130 100644 (file)
@@ -21,6 +21,7 @@ init_paths()
 
 from sample import IntArray2, IntArray3
 
+
 class NonTypeTemplateTest(unittest.TestCase):
 
     def testNonTypeTemplate(self):
@@ -32,7 +33,7 @@ class NonTypeTemplateTest(unittest.TestCase):
     def testArrayInitializer(self):
         if not hasNumPy:
             return
-        array3 = IntArray3(numpy.array([1, 2, 3], dtype = 'int32'))
+        array3 = IntArray3(numpy.array([1, 2, 3], dtype='int32'))
         self.assertEqual(array3.sum(), 6)
 
 
index d2a30c7ef1b6bd732f6e3bcc66adb65cb37b2461..7be239fc47d6d8ac88508526095a3b2debd19bbd 100644 (file)
@@ -13,6 +13,7 @@ init_paths()
 
 from sample import Color, Brush
 
+
 class TestNonZeroOperator(unittest.TestCase):
     def testColor(self):
         """Color has a Qt-style isNull()"""
index 9539469a1edd979fdc039d1b8a0b1c2df53b78eb..f714a4fc8ce7ff97ecf41768a957dc0e67e9197b 100644 (file)
@@ -13,6 +13,7 @@ init_paths()
 
 from sample import SizeF
 
+
 class NumericalTypedefTest(unittest.TestCase):
 
     def testNumericalTypedefExact(self):
@@ -32,5 +33,6 @@ class NumericalTypedefTest(unittest.TestCase):
         self.assertEqual(SizeF.passTypedefOfUnsignedShort(321), 321)
         self.assertNotEqual(SizeF.passTypedefOfUnsignedShort(123), 0)
 
+
 if __name__ == '__main__':
     unittest.main()
index af1e6d1bfa7843b5cacb84a942bf098d2c385450..42094a463ae741b98ecb140aa2014eaffcf52b20 100644 (file)
@@ -8,7 +8,7 @@ try:
     if bool(sysconfig.get_config_var('Py_DEBUG')):
         sys.exit(0)
     import numpy
-except:
+except:  # noqa: E722
     sys.exit(0)
 
 import os
@@ -21,6 +21,7 @@ from shiboken_paths import init_paths
 init_paths()
 from sample import PointF
 
+
 class TestNumpyTypes(unittest.TestCase):
 
     def testNumpyConverted(self):
@@ -35,6 +36,6 @@ class TestNumpyTypes(unittest.TestCase):
         self.assertAlmostEqual(p.x(), x)
         self.assertAlmostEqual(p.y(), y)
 
+
 if __name__ == "__main__":
     unittest.main()
-
index 6e90bfb35cdfc825f2d9b86fd70b73288527346e..ead68ba1385a52de231ba2670db32402c3018519 100644 (file)
@@ -68,7 +68,7 @@ class ObjectTypeTest(unittest.TestCase):
     def testNextInFocusChainCycle(self):
         parent = ObjectType()
         child = ObjectType(parent)
-        next_focus = child.nextInFocusChain()
+        next_focus = child.nextInFocusChain()  # noqa: F841
 
         Shiboken.invalidate(parent)
 
@@ -105,5 +105,6 @@ class ObjectTypeTest(unittest.TestCase):
         with self.assertRaises(AttributeError):
             o.typo
 
+
 if __name__ == '__main__':
     unittest.main()
index 4e552e887949a8ff9ac52d8a52801cba19d49d3f..285e2313bcb78df8efcd9f8392ea3cf1702acd7a 100644 (file)
@@ -13,6 +13,7 @@ init_paths()
 
 from sample import ObjectType
 
+
 class NamedArgsTest(unittest.TestCase):
 
     def testOneArgument(self):
@@ -35,18 +36,15 @@ class NamedArgsTest(unittest.TestCase):
         o.setObjectNameWithSize(size=6, name="pyside")
         self.assertEqual(o.objectName(), "pyside")
 
-
     def testUseDefaultValues(self):
         o = ObjectType()
 
         o.setObjectNameWithSize(size=3)
-        self.assertEqual(o.objectName(), "<un") # use name='unknown' default argument
+        self.assertEqual(o.objectName(), "<un")  # use name='unknown' default argument
 
         o.setObjectSplittedName("")
-        self.assertEqual(o.objectName(), "<unknown>") # user prefix='<unk' and suffix='nown>'
-
+        self.assertEqual(o.objectName(), "<unknown>")  # user prefix='<unk' and suffix='nown>'
 
 
 if __name__ == '__main__':
     unittest.main()
-
index 9dd3baf63de7a4ee7ced40ce9960114a2c56dd57..8f74af3abac2f3ddbc19474fc4240311c369010e 100644 (file)
@@ -10,7 +10,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import ObjectTypeByValue
 
 
 class ObjectTypeByValueTest (unittest.TestCase):
@@ -22,5 +22,6 @@ class ObjectTypeByValueTest (unittest.TestCase):
         # just to make sure it will segfault
         obj.prop.protectedValueTypeProperty.setY(2.0)
 
+
 if __name__ == "__main__":
     unittest.main()
index ea30f103ec93855eb9fc3e7f6abc799a55c45fcc..677b892816cb0479d2a1cbc242f7367c4bae6f63 100644 (file)
@@ -14,7 +14,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import ObjectType, ObjectTypeLayout
 
 
 class ObjectTypeLayoutTest(unittest.TestCase):
@@ -22,16 +22,15 @@ class ObjectTypeLayoutTest(unittest.TestCase):
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testOwnershipOverride(self):
-        l = ObjectTypeLayout()
+        lt = ObjectTypeLayout()
 
-        o1 = ObjectType(l)
+        o1 = ObjectType(lt)
         o1.setObjectName('o1')
 
         self.assertEqual(sys.getrefcount(o1), 3)
-        l.takeChild('o1')
+        lt.takeChild('o1')
         self.assertEqual(sys.getrefcount(o1), 2)
 
-
     def testSetNullLayout(self):
         '''ObjectType.setLayout(0).'''
         o2 = ObjectType()
@@ -57,7 +56,7 @@ class ObjectTypeLayoutTest(unittest.TestCase):
         self.assertEqual(c3.parent(), None)
 
         p1.setLayout(layout)
-        del p1 # This must kill c1, c2 and c3
+        del p1  # This must kill c1, c2 and c3
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
 
@@ -81,7 +80,7 @@ class ObjectTypeLayoutTest(unittest.TestCase):
         self.assertEqual(c3.parent(), None)
 
         p1.setLayout(layout)
-        del p1 # This must kill c1, c2 and c3
+        del p1  # This must kill c1, c2 and c3
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
 
@@ -91,7 +90,8 @@ class ObjectTypeLayoutTest(unittest.TestCase):
         self.assertRaises(RuntimeError, layout.objectName)
 
     def testObjectTypeLayoutTransference(self):
-        '''Transfer a layout from one ObjectType to another, so that all the items in the layout get reparented.'''
+        '''Transfer a layout from one ObjectType to another, so that all the items in
+           the layout get reparented.'''
         p1 = ObjectType()
         p2 = ObjectType()
         c1 = ObjectType()
@@ -154,7 +154,8 @@ class ObjectTypeLayoutTest(unittest.TestCase):
         self.assertRaises(RuntimeError, l2.objectName)
 
     def testObjectTypeLayoutInsideAnotherLayoutAndEveryoneCreatedInCpp(self):
-        '''Adds one ObjectTypeLayout to another and sets the parent to an ObjectType. All the objects are created in C++.'''
+        '''Adds one ObjectTypeLayout to another and sets the parent to an ObjectType.
+           All the objects are created in C++.'''
         p1 = ObjectType.create()
 
         l1 = ObjectTypeLayout.create()
@@ -192,7 +193,8 @@ class ObjectTypeLayoutTest(unittest.TestCase):
         self.assertRaises(RuntimeError, l2.objectName)
 
     def testTransferNestedLayoutsBetweenObjects(self):
-        '''Adds one ObjectTypeLayout to another, sets the parent to an ObjectType and then transfer it to another object.'''
+        '''Adds one ObjectTypeLayout to another, sets the parent to an ObjectType
+           and then transfer it to another object.'''
         p1 = ObjectType()
         p2 = ObjectType()
 
@@ -243,8 +245,8 @@ class ObjectTypeLayoutTest(unittest.TestCase):
         self.assertRaises(RuntimeError, l2.objectName)
 
     def testTransferNestedLayoutsBetweenObjectsAndEveryoneCreatedInCpp(self):
-        '''Adds one ObjectTypeLayout to another, sets the parent to an ObjectType and then transfer it to another object.
-        All the objects are created in C++.'''
+        '''Adds one ObjectTypeLayout to another, sets the parent to an ObjectType and then
+           transfer it to another object. All the objects are created in C++.'''
         p1 = ObjectType.create()
         p2 = ObjectType.create()
 
@@ -294,6 +296,6 @@ class ObjectTypeLayoutTest(unittest.TestCase):
         self.assertRaises(RuntimeError, l1.objectName)
         self.assertRaises(RuntimeError, l2.objectName)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index ae59366351038da369dcc5972f3b98d27360dda2..ceeee6c8d89ce1f1f777a771371e72f1d3cb7316 100644 (file)
@@ -10,7 +10,8 @@ from pathlib import Path
 sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
-from sample import *
+from sample import ObjectTypeOperators
+
 
 class ObjectTypeOperatorsTest(unittest.TestCase):
 
@@ -26,7 +27,7 @@ class ObjectTypeOperatorsTest(unittest.TestCase):
 
     def testPointerOpeators(self):
         a = ObjectTypeOperators("a")
-        b = ObjectTypeOperators("b")
+        b = ObjectTypeOperators("b")  # noqa: F841
         self.assertEqual(a + "bc", "abc")
         self.assertEqual("bc" + a, "bca")
         self.assertEqual("a", a)
@@ -36,5 +37,6 @@ class ObjectTypeOperatorsTest(unittest.TestCase):
         a = ObjectTypeOperators("a")
         self.assertNotEqual(a, "b")
 
+
 if __name__ == '__main__':
     unittest.main()
index 68e5edecc05f24ab0542d0571e38f810af0968c0..5fa6f824e59a4281462e18639c2f6c2a9c572ba7 100644 (file)
@@ -12,6 +12,7 @@ from shiboken_paths import init_paths
 init_paths()
 from sample import ObjectTypeHolder
 
+
 class TestObjectTypeReferenceAsVirtualMethodArgument(unittest.TestCase):
 
     def testBasic(self):
@@ -25,5 +26,6 @@ class TestObjectTypeReferenceAsVirtualMethodArgument(unittest.TestCase):
         holder = Holder('TheObjectFromC++')
         self.assertEqual(holder.callPassObjectTypeAsReference(), 'ThisIsTheObjectFromC++')
 
+
 if __name__ == '__main__':
     unittest.main()
index 466ddba82b42ca1bdc01b57e8610ee865fca00c0..87a8cdb1f8b231241bb351726259f8cd5fda6605 100644 (file)
@@ -15,11 +15,13 @@ init_paths()
 
 from sample import OddBoolUser, ComparisonTester, SpaceshipComparisonTester
 
+
 class DerivedOddBoolUser (OddBoolUser):
     def returnMyselfVirtual(self):
         return OddBoolUser()
     pass
 
+
 class OddBoolTest(unittest.TestCase):
 
     def testOddBoolUser(self):
@@ -30,13 +32,13 @@ class OddBoolTest(unittest.TestCase):
         self.assertEqual(obuTrue.oddBool(), True)
         self.assertEqual(obuTrue.callInvertedOddBool(), False)
 
-        self.assertEqual(obuTrue.oddBool() == True, True)
-        self.assertEqual(False == obuFalse.oddBool(), True)
-        self.assertEqual(obuTrue.oddBool() == obuFalse.oddBool(), False)
+        self.assertTrue(obuTrue.oddBool())
+        self.assertFalse(obuFalse.oddBool())
+        self.assertTrue(obuTrue.oddBool() != obuFalse.oddBool())
 
-        self.assertEqual(obuFalse.oddBool() != True, True)
-        self.assertEqual(True != obuFalse.oddBool(), True)
-        self.assertEqual(obuTrue.oddBool() != obuFalse.oddBool(), True)
+        self.assertFalse(obuFalse.oddBool())
+        self.assertFalse(obuFalse.oddBool())
+        self.assertTrue(obuTrue.oddBool() != obuFalse.oddBool())
 
     def testVirtuals(self):
         dobu = DerivedOddBoolUser()
index 3bdf431adbb8ce43fbd84267f8432732962c2db4..bcb154c52061be314d0ef9c426aa2865075f6efa 100644 (file)
@@ -13,6 +13,7 @@ init_paths()
 
 from sample import OnlyCopy, FriendOfOnlyCopy
 
+
 class ClassWithOnlyCopyCtorTest(unittest.TestCase):
     def testGetOne(self):
         obj = FriendOfOnlyCopy.createOnlyCopy(123)
@@ -34,5 +35,6 @@ class ClassWithOnlyCopyCtorTest(unittest.TestCase):
         obj = FriendOfOnlyCopy.createOnlyCopy(123)
         self.assertEqual(obj.value(), OnlyCopy.getValueFromReference(obj))
 
+
 if __name__ == '__main__':
     unittest.main()
index bb98f313d4d8683fc83f04e3e7f3de550d8d8b1e..84442306a249477e005fd306fccb1258549f1624 100644 (file)
@@ -13,7 +13,8 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import (Point, doubleLongLong, doubleShort, doubleUnsignedInt,
+                    doubleUnsignedLongLong)
 
 
 class OverflowTest(unittest.TestCase):
@@ -25,14 +26,16 @@ class OverflowTest(unittest.TestCase):
             return super().assertRaises(*args, **kwds)
 
     def testUnsignedInt(self):
-        '''C++ function receives an unsigned int argument and raise OverflowError if the value is negative.'''
+        '''C++ function receives an unsigned int argument and raise OverflowError
+           if the value is negative.'''
         val = 100
         self.assertEqual(doubleUnsignedInt(val), 2 * val)
         val *= -1
         self.assertRaises(OverflowError, doubleUnsignedInt, val)
 
     def testLongLong(self):
-        '''C++ function receives an long long argument and raise OverflowError if the value is negative.'''
+        '''C++ function receives an long long argument and raise OverflowError
+           if the value is negative.'''
         val = 100
         self.assertEqual(doubleLongLong(val), 2 * val)
         val = int(100)
@@ -41,7 +44,8 @@ class OverflowTest(unittest.TestCase):
         self.assertRaises(OverflowError, doubleLongLong, val)
 
     def testUnsignedLongLong(self):
-        '''C++ function receives an unsigned long long argument and raise OverflowError if the value is negative.'''
+        '''C++ function receives an unsigned long long argument and raise OverflowError
+           if the value is negative.'''
         val = 100
         self.assertEqual(doubleUnsignedLongLong(val), 2 * val)
         val = int(100)
@@ -59,13 +63,13 @@ class OverflowTest(unittest.TestCase):
     def testShortOverflow(self):
         '''Calls function with short parameter using an overflowing value.'''
         doubleShort(-3)
-        self.assertRaises(OverflowError, doubleShort, 0xFFFF*-1)
+        self.assertRaises(OverflowError, doubleShort, 0xFFFF * -1)
         self.assertRaises(OverflowError, doubleShort, 0xFFFF + 1)
 
     def testOverflowOnCtor(self):
         '''Calls object ctor with int parameter using overflowing values.'''
         self.assertRaises(OverflowError, Point, 42415335332353253, 42415335332353253)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 03da96581ea71d450e483eb88fdbedb523c50a0f..060d915103cf23aacce65965b1b07e2d30f2374a 100644 (file)
@@ -13,11 +13,14 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import (CustomOverloadSequence, ImplicitBase, ImplicitConv,
+                    ImplicitTarget, SortedOverload)
+
 
 class Dummy(object):
     pass
 
+
 class SimpleOverloadSorting(unittest.TestCase):
 
     def setUp(self):
@@ -63,6 +66,7 @@ class DeepOverloadSorting(unittest.TestCase):
         '''Deep Overload - (int, ImplicitBase *)'''
         self.assertEqual(self.obj.overloadDeep(1, ImplicitBase()), "ImplicitBase")
 
+
 class EnumOverIntSorting(unittest.TestCase):
     def testEnumOverInt(self):
         ic = ImplicitConv(ImplicitConv.CtorTwo)
index d6bd90877de294f744a2771b938c7c868c5e8e72..62fa8d8d24f0f9ffedfc22719b1d3fce8f119834 100644 (file)
@@ -21,11 +21,10 @@ def raisesWithErrorMessage(func, arguments, errorType, errorMsg):
     try:
         func(*arguments)
         return False
-    except Exception as err:
-        if type(err) != TypeError:
-            return False
-        if not errorMsg in str(err):
-            return False
+    except TypeError as err:
+        return errorMsg in str(err)
+    except Exception:
+        return False
     return True
 
 
@@ -178,12 +177,13 @@ class OverloadTest(unittest.TestCase):
     def testAcceptSequencePyObject(self):
         # Overload.acceptSequence(void*)
         overload = Overload()
+
         class Foo(object):
             pass
+
         foo = Foo()
         self.assertEqual(overload.acceptSequence(foo), Overload.Function5)
 
 
 if __name__ == '__main__':
     unittest.main()
-
index 1992974153f68671294a5868d29ecfc2b9e9d438..269b9729912f5b5458c5a673e16d7fe8a9dbf0ca 100644 (file)
@@ -39,6 +39,6 @@ class OverloadTest(unittest.TestCase):
         overload = Overload()
         self.assertEqual(overload.strBufferOverloads(bytes('', "UTF-8"), 0), Overload.Function1)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 8a3cdf490b88c29c0fae2ee9ce6a8be5217cf20d..8a55d3ab82af2b21468f7b20f0e20d310da50382 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import Polygon, Point
 
+
 class WrapperValidityOfArgumentsTest(unittest.TestCase):
     '''Wrapper validity tests for arguments.'''
 
@@ -25,17 +26,19 @@ class WrapperValidityOfArgumentsTest(unittest.TestCase):
         self.assertRaises(RuntimeError, Polygon.doublePolygonScale, poly)
 
     def testInvalidArgumentToConstructor(self):
-        '''Call to constructor using invalidated Python wrapper as argument should raise RuntimeError.'''
+        '''Call to constructor using invalidated Python wrapper as argument
+           should raise RuntimeError.'''
         pt = Point(1, 2)
         Polygon.stealOwnershipFromPython(pt)
         self.assertRaises(RuntimeError, Polygon, pt)
 
     def testInvalidArgumentWithImplicitConversion(self):
-        '''Call to method using invalidated Python wrapper to be implicitly converted should raise RuntimeError.'''
+        '''Call to method using invalidated Python wrapper to be implicitly converted
+           should raise RuntimeError.'''
         pt = Point(1, 2)
         Polygon.stealOwnershipFromPython(pt)
         self.assertRaises(RuntimeError, Polygon.doublePolygonScale, pt)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 2c789a72a94ff930090d41b6da4872682b874e10..25c6fea266d1e5c761c7abe03d7e36299aefeeb0 100644 (file)
@@ -30,5 +30,6 @@ class DeleteChildInCpp(unittest.TestCase):
         self.assertRaises(RuntimeError, child.objectName)
         self.assertEqual(parent.objectName(), 'parent')
 
+
 if __name__ == '__main__':
     unittest.main()
index b6f5ce2357201c91a05b9bc3e942380dc8e6a137..3ae1868150c66c661e011113ebe8ce430868b396 100644 (file)
@@ -35,5 +35,6 @@ class DeleteChildInPython(unittest.TestCase):
         new_child = parent.children()[0]
         self.assertEqual(new_child.objectName(), name)
 
+
 if __name__ == '__main__':
     unittest.main()
index 044ef9af61d549a04dcffeb0aaad035ffadd3220..8f654639c7cacf41179ed2895d3bba9c88a49517 100644 (file)
@@ -33,7 +33,7 @@ class DeleteParentTest(unittest.TestCase):
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
         self.assertRaises(RuntimeError, child.objectName)
-        self.assertEqual(sys.getrefcount(child), refcount_before-1)
+        self.assertEqual(sys.getrefcount(child), refcount_before - 1)
 
     @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount")
     def testParentDestructorMultipleChildren(self):
index e51b5555fb05f0899251454969fb2ae6e6facac1..37b7591e46551e9401dc9c1efa40a9fddcf45dfc 100644 (file)
@@ -21,11 +21,13 @@ class ExtObjectType(ObjectType):
         ObjectType.__init__(self)
         self.type_of_last_event = None
         self.last_event = None
+
     def event(self, event):
         self.last_event = event
         self.type_of_last_event = event.eventType()
         return True
 
+
 class MyObjectType (ObjectType):
     def __init__(self):
         super(MyObjectType, self).__init__()
@@ -35,7 +37,7 @@ class MyObjectType (ObjectType):
         self.callInvalidateEvent(ev)
         try:
             ev.eventType()
-        except:
+        except:  # noqa: E722
             self.fail = True
             raise
         return True
@@ -43,21 +45,25 @@ class MyObjectType (ObjectType):
     def invalidateEvent(self, ev):
         pass
 
+
 class ExtObjectTypeDerived(ObjectTypeDerived):
     def __init__(self):
         ObjectTypeDerived.__init__(self)
         self.type_of_last_event = None
         self.last_event = None
+
     def event(self, event):
         self.last_event = event
         self.type_of_last_event = event.eventType()
         return True
 
+
 class OwnershipInvalidateAfterUseTest(unittest.TestCase):
     '''Ownership tests for cases of invalidation of Python wrapper after use.'''
 
     def testInvalidateAfterUse(self):
-        '''In ObjectType.event(Event*) the wrapper object created for Event must me marked as invalid after the method is called.'''
+        '''In ObjectType.event(Event*) the wrapper object created for Event
+           must me marked as invalid after the method is called.'''
         eot = ExtObjectType()
         eot.causeEvent(Event.SOME_EVENT)
         self.assertEqual(eot.type_of_last_event, Event.SOME_EVENT)
@@ -84,6 +90,6 @@ class OwnershipInvalidateAfterUseTest(unittest.TestCase):
         self.assertEqual(eot.type_of_last_event, Event.SOME_EVENT)
         self.assertRaises(RuntimeError, eot.last_event.eventType)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 868c8593165a4b5202075e19d248ca7f0e5cb886..77b7c576ceee9d121533c3856e7c0c6d4e379af9 100644 (file)
@@ -49,6 +49,6 @@ class InvalidateChildTest(unittest.TestCase):
         self.assertEqual(child1.objectName(), 'child1')
         self.assertRaises(RuntimeError, child2.objectName)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 66d6ed5d2e36a545ceb1ccf722659eb031180c15..8cbefc30cc7b100d98d1a05526c6a94c93c9a04f 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import Point, BlackBox
 
+
 class OwnershipInvalidateNonPolymorphicTest(unittest.TestCase):
     '''The BlackBox class has cases of ownership transference between Python and C++.'''
 
@@ -27,6 +28,6 @@ class OwnershipInvalidateNonPolymorphicTest(unittest.TestCase):
         p1_ret = bb.retrievePoint(p1_ticket)
         self.assertEqual(p1_ret, Point(10, 20))
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 82ecafa7d674fc89fa2a9232068918494515ad01..c721a212c0980c28ceb090492dbbb8bd5efa69d3 100644 (file)
@@ -34,7 +34,7 @@ class InvalidateParentTest(unittest.TestCase):
         grandchild2.setParent(child2)
         bbox = BlackBox()
 
-        bbox.keepObjectType(parent) # Should invalidate the parent
+        bbox.keepObjectType(parent)  # Should invalidate the parent
 
         self.assertRaises(RuntimeError, parent.objectName)
         # some children still valid they are wrapper classes
@@ -43,6 +43,6 @@ class InvalidateParentTest(unittest.TestCase):
         self.assertEqual(grandchild1.objectName(), "grandchild1")
         self.assertRaises(RuntimeError, grandchild2.objectName)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index acacbf461ad57c2dfadf2b406902a89266165ad2..304223063ea385aaf4b8f932b4152f7817288a50 100644 (file)
@@ -16,6 +16,7 @@ import sys
 
 from sample import ObjectType
 
+
 class ExtObjectType(ObjectType):
     def __init__(self):
         ObjectType.__init__(self)
@@ -108,4 +109,3 @@ class ReparentingTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index d1eccb4f630245aba410328f3bf1952be5611f61..0e9f08b7250168d7f0489b5128df2e7c731e0bcd 100644 (file)
@@ -16,6 +16,7 @@ init_paths()
 
 from sample import ObjectType, BlackBox
 
+
 class BlackBoxTest(unittest.TestCase):
     '''The BlackBox class has cases of ownership transference between C++ and Python.'''
 
@@ -29,12 +30,13 @@ class BlackBoxTest(unittest.TestCase):
         o2.setObjectName('object2')
         o2_refcnt = sys.getrefcount(o2)
         bb = BlackBox()
-        o1_ticket = bb.keepObjectType(o1)
+        o1_ticket = bb.keepObjectType(o1)  # noqa: F841
         o2_ticket = bb.keepObjectType(o2)
         self.assertEqual(set(bb.objects()), set([o1, o2]))
         self.assertEqual(str(o1.objectName()), 'object1')
         self.assertEqual(str(o2.objectName()), 'object2')
-        self.assertEqual(sys.getrefcount(o1), o1_refcnt + 1) # PySide give +1 ref to object with c++ ownership
+        # PySide give +1 ref to object with c++ ownership
+        self.assertEqual(sys.getrefcount(o1), o1_refcnt + 1)
         self.assertEqual(sys.getrefcount(o2), o2_refcnt + 1)
         o2 = bb.retrieveObjectType(o2_ticket)
         self.assertEqual(sys.getrefcount(o2), o2_refcnt)
@@ -48,9 +50,9 @@ class BlackBoxTest(unittest.TestCase):
     def testBlackBoxReleasingUnknownObjectType(self):
         '''Asks BlackBox to release an unknown ObjectType.'''
         o1 = ObjectType()
-        o2 = ObjectType()
+        o2 = ObjectType()  # noqa: F841
         bb = BlackBox()
-        o1_ticket = bb.keepObjectType(o1)
+        o1_ticket = bb.keepObjectType(o1)  # noqa: F841
         o3 = bb.retrieveObjectType(-5)
         self.assertEqual(o3, None)
 
@@ -59,11 +61,11 @@ class BlackBoxTest(unittest.TestCase):
         '''Ownership transference using a C++ created object.'''
         o1 = ObjectType.create()
         o1.setObjectName('object1')
-        o1_refcnt = sys.getrefcount(o1)
+        o1_refcnt = sys.getrefcount(o1)  # noqa: F841
         bb = BlackBox()
-        o1_ticket = bb.keepObjectType(o1)
+        o1_ticket = bb.keepObjectType(o1)  # noqa: F841
         self.assertRaises(RuntimeError, o1.objectName)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 278219434beeb549d6796586d8089b1cd176c8d8..4bd5c697c54ea24a42a5fa15748078a9f1bd428b 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import PairUser
 
+
 class ExtendedPairUser(PairUser):
     def __init__(self):
         PairUser.__init__(self)
@@ -24,6 +25,7 @@ class ExtendedPairUser(PairUser):
         self.create_pair_called = True
         return (7, 13)
 
+
 class PairConversionTest(unittest.TestCase):
     '''Test case for std::pair container conversions'''
 
@@ -48,14 +50,16 @@ class PairConversionTest(unittest.TestCase):
         self.assertEqual(cp, (cpx0, cpx1))
 
     def testSumPair(self):
-        '''Test method that sums the items of a pair using values of the types expected by C++ (int and double)'''
+        '''Test method that sums the items of a pair using values of the types
+           expected by C++ (int and double)'''
         pu = PairUser()
         pair = (3, 7.13)
         result = pu.sumPair(pair)
         self.assertEqual(result, sum(pair))
 
     def testSumPairDifferentTypes(self):
-        '''Test method that sums the items of a pair using values of types different from the ones expected by C++ (int and double)'''
+        '''Test method that sums the items of a pair using values of types different
+           from the ones expected by C++ (int and double)'''
         pu = PairUser()
         pair = (3.3, 7)
         result = pu.sumPair(pair)
@@ -71,7 +75,8 @@ class PairConversionTest(unittest.TestCase):
         self.assertEqual(result, pair)
 
     def testConversionInBothDirectionsWithSimilarContainer(self):
-        '''Test converting a list, instead of the expected tuple, from Python to C++ and the other way around.'''
+        '''Test converting a list, instead of the expected tuple, from Python to C++
+           and the other way around.'''
         pu = PairUser()
         pair = [3, 5]
         pu.setPair(pair)
@@ -79,6 +84,6 @@ class PairConversionTest(unittest.TestCase):
         self.assertNotEqual(result, pair)
         self.assertEqual(result, tuple(pair))
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 88684dc38b57d8d2f41c1f518d7b63c6ac4851ed..106f3bd61d1ce6b9ad90065740853ce0926bb88c 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import Color, Pen, SampleNamespace
 
+
 class TestPen(unittest.TestCase):
     '''Simple test case for Pen.'''
 
index 5e74153954838581ecb61cca28557352e0888c53..f86c0f423596fcd2698d27359e3052868cae70d6 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import Point
 
+
 class PointTest(unittest.TestCase):
     '''Test case for Point class, including operator overloads.'''
 
@@ -92,5 +93,6 @@ class PointTest(unittest.TestCase):
         expected = Point((pt1.x() + pt2.x()) / 2.0, (pt1.y() + pt2.y()) / 2.0)
         self.assertEqual(pt1.midpoint(pt2), expected)
 
+
 if __name__ == '__main__':
     unittest.main()
index be2faa1187cb03c446b598f1769bd89870e619f8..633525a9c0cae69d547aff5b36ea048bfb4b7360 100644 (file)
@@ -15,8 +15,10 @@ init_paths()
 
 from sample import PointerHolder
 
+
 class TestPointerHolder(unittest.TestCase):
-    '''Test cases for a class that holds an arbitraty pointer and is modified to hold an PyObject.'''
+    '''Test cases for a class that holds an arbitraty pointer and
+       is modified to hold an PyObject.'''
 
     def testStoringAndRetrievingPointer(self):
         ph = PointerHolder('Hello')
@@ -31,9 +33,9 @@ class TestPointerHolder(unittest.TestCase):
         a = (1, 2, 3)
         refcnt = sys.getrefcount(a)
         ph = PointerHolder(a)
-        ptr = ph.pointer()
+        ptr = ph.pointer()  # noqa: F841
         self.assertEqual(sys.getrefcount(a), refcnt + 1)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 02719957485a48be3e21dd912bc2fe245dd39211..4da1a89c604702e9590b1644998becbe0dc5248a 100644 (file)
@@ -27,7 +27,6 @@ from shiboken_paths import init_paths
 init_paths()
 from sample import IntArray2, VirtualMethods
 
-import shiboken6
 from shibokensupport.signature import get_signature
 
 import typing
index 53616aecb6e051a221449eb6e4fa3634b34f14cc..91c58eb1d4334f691770c2b367194e2f5c2c6656 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import PointF
 
+
 class PointFTest(unittest.TestCase):
     '''Test case for PointF class, including operator overloads.'''
 
@@ -45,5 +46,6 @@ class PointFTest(unittest.TestCase):
         expected = PointF((pt1.x() + pt2.x()) / 2.0, (pt1.y() + pt2.y()) / 2.0)
         self.assertEqual(pt1.midpoint(pt2), expected)
 
+
 if __name__ == '__main__':
     unittest.main()
index 790ed39d51f2e1b32dc809bfe6a35085b334ad03..0b9fe2249f910b21be36bc7c4115796645401c35 100644 (file)
@@ -12,6 +12,7 @@ from shiboken_paths import init_paths
 init_paths()
 import sample
 
+
 class PrimitiveReferenceArgumentTest(unittest.TestCase):
 
     def testIntReferenceArgument(self):
@@ -29,5 +30,6 @@ class PrimitiveReferenceArgumentTest(unittest.TestCase):
         self.assertNotEqual(sample.acceptOddBoolReference(True), False)
         self.assertNotEqual(sample.acceptOddBoolReference(False), True)
 
+
 if __name__ == '__main__':
     unittest.main()
index 235882997b723845eddca49e4ed32acc7e6866e2..63040388d11c7d529736f4d4b62ccb3ede33e4c5 100644 (file)
@@ -64,6 +64,6 @@ class PrivateCtorTest(unittest.TestCase):
         self.assertEqual(pd3.instanceCalls(), calls + 2)
         self.assertEqual(sys.getrefcount(pd3), refcnt)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 777a9923b6da5cab69715b517fc09f32f192f288..651f63b15213ec7d924088155dc8ab5a97d1d1d6 100644 (file)
@@ -80,6 +80,6 @@ class PrivateDtorTest(unittest.TestCase):
 
         self.assertLess(abs(before - after), 5)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 9538125f54ce45f607d17c434e0413400206f349..e4ccf721dfc24533326f8984ceb756fc55a971d9 100644 (file)
@@ -16,42 +16,51 @@ init_paths()
 
 from sample import cacheSize
 from sample import ProtectedNonPolymorphic, ProtectedVirtualDestructor
-from sample import ProtectedPolymorphic, ProtectedPolymorphicDaughter, ProtectedPolymorphicGrandDaughter
+from sample import (ProtectedPolymorphic, ProtectedPolymorphicDaughter,
+                    ProtectedPolymorphicGrandDaughter)
 from sample import createProtectedProperty, ProtectedProperty, ProtectedEnumClass
 from sample import PrivateDtor
 from sample import Event, ObjectType, Point
 
+
 class ExtendedProtectedPolymorphic(ProtectedPolymorphic):
     def __init__(self, name):
         ProtectedPolymorphic.__init__(self, name)
         self.protectedName_called = False
+
     def protectedName(self):
         self.protectedName_called = True
         self._name = 'Extended' + ProtectedPolymorphic.protectedName(self)
         return self._name
 
+
 class ExtendedProtectedPolymorphicDaughter(ProtectedPolymorphicDaughter):
     def __init__(self, name):
         self.protectedName_called = False
         ProtectedPolymorphicDaughter.__init__(self, name)
+
     def protectedName(self):
         self.protectedName_called = True
         self._name = 'ExtendedDaughter' + ProtectedPolymorphicDaughter.protectedName(self)
         return self._name
 
+
 class ExtendedProtectedPolymorphicGrandDaughter(ProtectedPolymorphicGrandDaughter):
     def __init__(self, name):
         self.protectedName_called = False
         ProtectedPolymorphicGrandDaughter.__init__(self, name)
+
     def protectedName(self):
         self.protectedName_called = True
         self._name = 'ExtendedGrandDaughter' + ProtectedPolymorphicGrandDaughter.protectedName(self)
         return self._name
 
+
 class ExtendedProtectedVirtualDestructor(ProtectedVirtualDestructor):
     def __init__(self):
         ProtectedVirtualDestructor.__init__(self)
 
+
 class ProtectedNonPolymorphicTest(unittest.TestCase):
     '''Test cases for protected method in a class without virtual methods.'''
 
@@ -81,6 +90,7 @@ class ProtectedNonPolymorphicTest(unittest.TestCase):
         self.assertEqual(p.dataTypeName(1), 'integer')
         self.assertEqual(p.dataTypeName(Point(1, 2)), 'pointer')
 
+
 class ProtectedPolymorphicTest(unittest.TestCase):
     '''Test cases for protected method in a class with virtual methods.'''
 
@@ -110,6 +120,8 @@ class ProtectedPolymorphicTest(unittest.TestCase):
         self.assertTrue(p.protectedName_called)
         self.assertEqual(p.protectedName(), name)
         self.assertEqual(ProtectedPolymorphic.protectedName(p), original_name)
+
+
 class ProtectedPolymorphicDaugherTest(unittest.TestCase):
     '''Test cases for protected method in a class inheriting for a class with virtual methods.'''
 
@@ -153,6 +165,7 @@ class ProtectedPolymorphicGrandDaugherTest(unittest.TestCase):
         self.assertEqual(p.protectedName(), name)
         self.assertEqual(ProtectedPolymorphicGrandDaughter.protectedName(p), original_name)
 
+
 class ProtectedVirtualDtorTest(unittest.TestCase):
     '''Test cases for protected virtual destructor.'''
 
@@ -200,15 +213,18 @@ class ProtectedVirtualDtorTest(unittest.TestCase):
 class ExtendedProtectedEnumClass(ProtectedEnumClass):
     def __init__(self):
         ProtectedEnumClass.__init__(self)
+
     def protectedEnumMethod(self, value):
         if value == ProtectedEnumClass.ProtectedItem0:
             return ProtectedEnumClass.ProtectedItem1
         return ProtectedEnumClass.ProtectedItem0
+
     def publicEnumMethod(self, value):
         if value == ProtectedEnumClass.PublicItem0:
             return ProtectedEnumClass.PublicItem1
         return ProtectedEnumClass.PublicItem0
 
+
 class ProtectedEnumTest(unittest.TestCase):
     '''Test cases for protected enum.'''
 
@@ -223,47 +239,66 @@ class ProtectedEnumTest(unittest.TestCase):
 
         self.assertEqual(type(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedEnum)
 
-        self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem0)
-        self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem1)
-
-        self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem0)
-        self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem1)
+        self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0),
+                         ProtectedEnumClass.ProtectedItem0)
+        self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem1),
+                         ProtectedEnumClass.ProtectedItem1)
+        self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0),
+                         ProtectedEnumClass.ProtectedItem0)
+        self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1),
+                         ProtectedEnumClass.ProtectedItem1)
 
     def testProtectedMethodWithPublicEnumArgument(self):
         '''Calls protected method with public enum argument.'''
         obj = ProtectedEnumClass()
 
-        self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem0)
-        self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem1)
+        self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0),
+                         ProtectedEnumClass.PublicItem0)
+        self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1),
+                         ProtectedEnumClass.PublicItem1)
 
-        self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem0)
-        self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem1)
+        self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0),
+                         ProtectedEnumClass.PublicItem0)
+        self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1),
+                         ProtectedEnumClass.PublicItem1)
 
     def testOverriddenProtectedMethodWithProtectedEnumArgument(self):
         '''Calls overridden protected method with protected enum argument.'''
         obj = ExtendedProtectedEnumClass()
 
-        self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem1)
-        self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem0)
+        self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0),
+                         ProtectedEnumClass.ProtectedItem1)
+        self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem1),
+                         ProtectedEnumClass.ProtectedItem0)
 
-        self.assertEqual(ProtectedEnumClass.protectedEnumMethod(obj, ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem0)
-        self.assertEqual(ProtectedEnumClass.protectedEnumMethod(obj, ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem1)
+        self.assertEqual(ProtectedEnumClass.protectedEnumMethod(obj, ProtectedEnumClass.ProtectedItem0),  # noqa: E501
+                         ProtectedEnumClass.ProtectedItem0)
+        self.assertEqual(ProtectedEnumClass.protectedEnumMethod(obj,
+                         ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem1)
 
-        self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedItem1)
-        self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem0)
+        self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0),
+                         ProtectedEnumClass.ProtectedItem1)
+        self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1),
+                         ProtectedEnumClass.ProtectedItem0)
 
     def testOverriddenProtectedMethodWithPublicEnumArgument(self):
         '''Calls overridden protected method with public enum argument.'''
         obj = ExtendedProtectedEnumClass()
 
-        self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem1)
-        self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem0)
+        self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0),
+                         ProtectedEnumClass.PublicItem1)
+        self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1),
+                         ProtectedEnumClass.PublicItem0)
 
-        self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem0)
-        self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem1)
+        self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem0),
+                         ProtectedEnumClass.PublicItem0)
+        self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem1),
+                         ProtectedEnumClass.PublicItem1)
 
-        self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0), ProtectedEnumClass.PublicItem1)
-        self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1), ProtectedEnumClass.PublicItem0)
+        self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0),
+                         ProtectedEnumClass.PublicItem1)
+        self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1),
+                         ProtectedEnumClass.PublicItem0)
 
 
 class ProtectedPropertyTest(unittest.TestCase):
@@ -361,6 +396,6 @@ class PrivateDtorProtectedMethodTest(unittest.TestCase):
         self.assertEqual(obj.instanceCalls(), 2)
         self.assertEqual(obj.instanceCalls(), obj.protectedInstanceCalls())
 
+
 if __name__ == '__main__':
     unittest.main()
-
index a257d5944dbbd3c1235eb7c7bed40f3a5a62f1ee..d60f9cf355cd297e7e0834cbbc020bd26be2f5d2 100644 (file)
@@ -12,6 +12,7 @@ from shiboken_paths import init_paths
 init_paths()
 import sample
 
+
 class PStrListTest(unittest.TestCase):
 
     def testPStrList(self):
@@ -26,5 +27,6 @@ class PStrListTest(unittest.TestCase):
         lst = sample.createListOfPStr(a, b)
         self.assertEqual(lst, [a, b])
 
+
 if __name__ == '__main__':
     unittest.main()
index 3472457e8d711e3d36cbb3288d73285d5c125e24..ec64c1e31389e6805f647413c5c8f32dfce99d95 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import Point
 
+
 class PyStrTest(unittest.TestCase):
     '''Test case for definition of __str__ method.'''
 
@@ -23,6 +24,6 @@ class PyStrTest(unittest.TestCase):
         pt = Point(5, 2)
         self.assertEqual(str(pt), 'Point(5.0, 2.0)')
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 03a75b8246b132f4771aa948fc1d60f107afe7db..65398b5c676455dfc7690ff8fe0aa21abdf480b9 100644 (file)
@@ -36,7 +36,7 @@ class Producer(threading.Thread):
 
     def run(self):
         while self.runs < self.max_runs:
-            value = int(random()*10) % 10
+            value = int(random() * 10) % 10
             self.bucket.push(value)
             self.production_list.append(value)
             logging.debug(f'PRODUCER - pushed {value}')
@@ -66,6 +66,7 @@ class Consumer(threading.Thread):
                 logging.debug('CONSUMER - empty bucket')
             time.sleep(0.01)
 
+
 class ProducerConsumer(unittest.TestCase):
     '''Basic test case for producer-consumer QThread'''
 
@@ -91,8 +92,5 @@ class ProducerConsumer(unittest.TestCase):
         self.assertEqual(prod.production_list, cons.consumption_list)
 
 
-
-
-
 if __name__ == '__main__':
     unittest.main()
index f8c7f017d9a58a70a88cdbcbcc19f433c5bd9559..1d19de9414ed51a92dce48837b517dc14e4415ca 100644 (file)
@@ -15,8 +15,10 @@ init_paths()
 
 from sample import countCharacters
 
+
 class ReceiveNullCStringTest(unittest.TestCase):
-    '''Test case for a function that could receive a NULL pointer in a '[const] char*' parameter.'''
+    '''Test case for a function that could receive a NULL pointer in a '[const] char*'
+       parameter.'''
 
     def testBasic(self):
         '''The test function should be working for the basic cases.'''
@@ -29,6 +31,6 @@ class ReceiveNullCStringTest(unittest.TestCase):
         '''The test function returns '-1' when receives a None value instead of a string.'''
         self.assertEqual(countCharacters(None), -1)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index e590a7e4e42c7a18f1ed9b67b67987f5d74ce7a2..1b6dd3a7a331d6313282b5008e41256902ec2387 100644 (file)
@@ -13,7 +13,8 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import Reference, Str
+
 
 class ExtendedReference(Reference):
     def __init__(self):
@@ -48,7 +49,7 @@ class ReferenceTest(unittest.TestCase):
     def testCantSegFaultWhenReceiveNone(self):
         '''do not segfault when receiving None as argument.'''
         s = Str()
-        self.assertTrue(None == s)
+        self.assertFalse(bool(s))
 
     def testMethodThatReceivesConstReference(self):
         '''Test a method that receives a const reference to an object as argument.'''
@@ -57,29 +58,33 @@ class ReferenceTest(unittest.TestCase):
         self.assertEqual(Reference.usesConstReference(r), objId)
 
     def testModificationOfReference(self):
-        '''Tests if the identity of a reference argument is preserved when passing it to be altered in C++.'''
+        '''Tests if the identity of a reference argument is preserved when passing
+           it to be altered in C++.'''
         objId = 123
         r1 = Reference(objId)
         r1.alterReferenceIdVirtual(r1)
         self.assertEqual(r1.objId(), objId * Reference.multiplier())
 
     def testModificationOfReferenceCallingAVirtualIndirectly(self):
-        '''Tests if the identity of a reference argument is preserved when passing it to be altered in C++ through a method that calls a virtual method.'''
+        '''Tests if the identity of a reference argument is preserved when passing it
+           to be altered in C++ through a method that calls a virtual method.'''
         objId = 123
         r1 = Reference(objId)
         r1.callAlterReferenceIdVirtual(r1)
         self.assertEqual(r1.objId(), objId * Reference.multiplier())
 
     def testModificationOfReferenceCallingAReimplementedVirtualIndirectly(self):
-        '''Test if a Python override of a virtual method with a reference parameter called from C++ alters the argument properly.'''
+        '''Test if a Python override of a virtual method with a reference parameter
+           called from C++ alters the argument properly.'''
         objId = 123
         r = Reference(objId)
         er = ExtendedReference()
-        result = er.callAlterReferenceIdVirtual(r)
+        result = er.callAlterReferenceIdVirtual(r)  # noqa: F841
         self.assertEqual(r.objId(), objId * er.multiplier)
 
     def testReimplementedVirtualMethodCallWithReferenceParameter(self):
-        '''Test if a Python override of a virtual method with a reference parameter is correctly called from C++.'''
+        '''Test if a Python override of a virtual method with a reference parameter
+           is correctly called from C++.'''
         inc = 9
         objId = 123
         r = Reference(objId)
@@ -88,7 +93,8 @@ class ReferenceTest(unittest.TestCase):
         self.assertEqual(result, objId + inc + er.reference_inc)
 
     def testReimplementedVirtualMethodCallWithConstReferenceParameter(self):
-        '''Test if a Python override of a virtual method with a const reference parameter is correctly called from C++.'''
+        '''Test if a Python override of a virtual method with a const reference
+           parameter is correctly called from C++.'''
         inc = 9
         objId = 123
         r = Reference(objId)
@@ -96,6 +102,6 @@ class ReferenceTest(unittest.TestCase):
         result = er.callUsesConstReferenceVirtual(r, inc)
         self.assertEqual(result, objId + inc + er.const_reference_inc)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 94bb1608b5ca8938eb4a65617137842a67db68e5..942c7ea290c2e6983b31beb50346cce408550257 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import VirtualMethods, Str
 
+
 class ExtendedVirtualMethods(VirtualMethods):
     def __init__(self):
         VirtualMethods.__init__(self)
@@ -72,6 +73,6 @@ class ReferenceToPointerTest(unittest.TestCase):
         self.assertTrue(ok)
         self.assertEqual(string, Str(obj.prefix + 'foo'))
 
+
 if __name__ == '__main__':
     unittest.main()
-
index b6a9a8fa4226d55d30213734b6a22a19ccf5ae18..b08438ef35dfe642f9bc36529ea30904f3043e6d 100644 (file)
@@ -16,8 +16,6 @@ init_paths()
 
 from sample import RenamedValue, RenamedUser
 
-from shiboken6 import Shiboken
-
 from shibokensupport.signature import get_signature
 
 
@@ -37,6 +35,5 @@ class RenamingTest(unittest.TestCase):
                                  actual_signature))
 
 
-
 if __name__ == '__main__':
     unittest.main()
index 46d19e9f7985a7da4daab6d90d4860e7b533516c..2c4f07c653645fa8098d1103020b7641b2d80466 100644 (file)
@@ -13,7 +13,9 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import returnNullPrimitivePointer, returnNullValueTypePointer, returnNullObjectTypePointer
+from sample import (returnNullPrimitivePointer, returnNullValueTypePointer,
+                    returnNullObjectTypePointer)
+
 
 class ReturnNullTest(unittest.TestCase):
     '''Test case for functions that could return a NULL pointer.'''
@@ -33,6 +35,6 @@ class ReturnNullTest(unittest.TestCase):
         o = returnNullValueTypePointer()
         self.assertEqual(o, None)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index e764b41a4142ab5893968a9a65e302393cb76b3b..3146d0fafd9df4acd028e93d4615a3d1d1496c5e 100644 (file)
@@ -11,7 +11,8 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import Expression
+
 
 class TestRichCompare(unittest.TestCase):
 
@@ -22,5 +23,6 @@ class TestRichCompare(unittest.TestCase):
         d = a + c < b + a
         self.assertEqual(d.toString(), "((2+(2+3))<(3+2))")
 
+
 if __name__ == '__main__':
     unittest.main()
index 225eae2257798f2eced0420ec8ba2a0f775dc15f..19b2f708d451d0fc4830e0791a4d3d5e8033a06e 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 import sample
 
+
 class ModuleTest(unittest.TestCase):
     '''Test case for module and global functions'''
 
@@ -50,7 +51,6 @@ class ModuleTest(unittest.TestCase):
         sample.testNullPtrT(None)
         self.assertRaises(TypeError, sample.testNullPtrT, 42)
 
-
     def testRValueRefsWithValueTypes(self):
         """Passing value types by rvalue refs: For value types, nothing should
            happen since the argument is copied in the call and the copy is
@@ -74,4 +74,3 @@ class ModuleTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 1217bd9a8027b85227a8a5f5d65dab8c71cd8e5d..55c894a354677452e49d3e13a0e149b296b061eb 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import SimpleFile
 
+
 class SimpleFileTest(unittest.TestCase):
     '''Test cases for SimpleFile class.'''
 
@@ -54,6 +55,6 @@ class SimpleFileTest(unittest.TestCase):
         self.assertRaises(IOError, f.open)
         self.assertEqual(f.size(), 0)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 179a961d970053225314535d2ac730e64cb76215..069ce59b39dbad9fd7f526f156d8d84c5bad0a35 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import Size
 
+
 class PointTest(unittest.TestCase):
     '''Test case for Size class, including operator overloads.'''
 
@@ -94,6 +95,6 @@ class PointTest(unittest.TestCase):
         self.assertTrue(s1 > s2)
         self.assertFalse(s2 > s1)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index e176b334797638d2fa33492c419aaa549be4c181..cf08892998a0d0da6d420323dc494504ad1f2db6 100644 (file)
@@ -15,16 +15,20 @@ init_paths()
 
 from sample import SimpleFile
 
+
 class SimpleFile2 (SimpleFile):
     def exists(self):
         return "Mooo"
 
+
 class SimpleFile3 (SimpleFile):
     pass
 
+
 class SimpleFile4 (SimpleFile):
     exists = 5
 
+
 class StaticNonStaticMethodsTest(unittest.TestCase):
     '''Test cases for overloads involving static and non-static versions of a method.'''
 
@@ -79,9 +83,9 @@ class StaticNonStaticMethodsTest(unittest.TestCase):
 
     def testDuckPunchingStaticNonStaticMethod(self):
         f = SimpleFile(os.fspath(self.existing_filename))
-        f.exists = lambda : "Meee"
+        f.exists = lambda: "Meee"
         self.assertEqual(f.exists(), "Meee")
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 97df7645292dd1de10994198c954eeaf6e0144ac..c06fd64282eb48655acf5cd3171a5a90577da5c9 100644 (file)
@@ -2,7 +2,8 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
-'''Test cases for a method that receives a reference to class that is implicitly convertible from a Python native type.'''
+'''Test cases for a method that receives a reference to class that is implicitly
+   convertible from a Python native type.'''
 
 import os
 import sys
@@ -15,6 +16,7 @@ init_paths()
 
 from sample import Str
 
+
 class StrTest(unittest.TestCase):
     '''Test cases for thr Str class.'''
 
@@ -31,39 +33,39 @@ class StrTest(unittest.TestCase):
         self.assertEqual(str(s1), 'This is Sparta!')
 
     def testPassPythonTypeImplictlyConvertibleToAClassUsedAsReference(self):
-        '''Test passing a Python class implicitly convertible to a wrapped class that is expected to be passed as reference.'''
+        '''Test passing a Python class implicitly convertible to a wrapped class
+           that is expected to be passed as reference.'''
         s1 = Str('This is %VAR!').arg('Athens')
         self.assertEqual(str(s1), 'This is Athens!')
 
     def testSequenceOperators(self):
         s1 = Str("abcdef")
-        self.assertEqual(len(s1), 6);
-        self.assertEqual(len(Str()), 0);
+        self.assertEqual(len(s1), 6)
+        self.assertEqual(len(Str()), 0)
 
         # getitem
-        self.assertEqual(s1[0], "a");
-        self.assertEqual(s1[1], "b");
-        self.assertEqual(s1[2], "c");
-        self.assertEqual(s1[3], "d");
-        self.assertEqual(s1[4], "e");
-        self.assertEqual(s1[5], "f");
-        self.assertEqual(s1[-1], "f");
-        self.assertEqual(s1[-2], "e");
+        self.assertEqual(s1[0], "a")
+        self.assertEqual(s1[1], "b")
+        self.assertEqual(s1[2], "c")
+        self.assertEqual(s1[3], "d")
+        self.assertEqual(s1[4], "e")
+        self.assertEqual(s1[5], "f")
+        self.assertEqual(s1[-1], "f")
+        self.assertEqual(s1[-2], "e")
 
         self.assertRaises(TypeError, s1.__getitem__, 6)
 
         # setitem
         s1[0] = 'A'
         s1[1] = 'B'
-        self.assertEqual(s1[0], 'A');
-        self.assertEqual(s1[1], 'B');
+        self.assertEqual(s1[0], 'A')
+        self.assertEqual(s1[1], 'B')
         self.assertRaises(TypeError, s1.__setitem__(6, 67))
 
     def testReverseOperator(self):
         s1 = Str("hello")
-        n1 = 2
-        self.assertEqual(s1+2, "hello2")
-        self.assertEqual(2+s1, "2hello")
+        self.assertEqual(s1 + 2, "hello2")
+        self.assertEqual(2 + s1, "2hello")
 
     def testToIntError(self):
         self.assertEqual(Str('Z').toInt(), (0, False))
@@ -90,6 +92,6 @@ class StrTest(unittest.TestCase):
         self.assertEqual(val, int(str(hexa), 16))
         self.assertEqual(hexa.toInt(), (0, False))
 
+
 if __name__ == '__main__':
     unittest.main()
-
index f768f9c63f1e6e9ff1f3cd43e7f0c60b3bf30a52..2bfb80b6722600d8ca46832cffcc386989af1aa7 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import Str, StrList
 
+
 class StrListTest(unittest.TestCase):
     '''Test cases for StrList class that inherits from std::list<Str>.'''
 
@@ -88,5 +89,6 @@ class StrListTest(unittest.TestCase):
         self.assertEqual(len(sl), 2)
         self.assertEqual(sl, (Str('Foo'), 'Bar'))
 
+
 if __name__ == '__main__':
     unittest.main()
index f458ad0d2c51772393fed9227acab4a46b030481..11279c7ec0d0915b191ef3aba7bb163aa8580eab 100644 (file)
@@ -14,7 +14,8 @@ init_paths()
 from sample import Photon
 
 '''This tests classes that inherit from template classes,
-simulating a situation found in Qt's phonon module.'''
+   simulating a situation found in Qt's phonon module.'''
+
 
 class TemplateInheritingClassTest(unittest.TestCase):
     def testClassBasics(self):
@@ -57,5 +58,6 @@ class TemplateInheritingClassTest(unittest.TestCase):
         self.assertEqual(obj2, obj2.passPointerThrough(obj2))
         self.assertRaises(TypeError, obj1.passPointerThrough, obj2)
 
+
 if __name__ == '__main__':
     unittest.main()
index 9b32aaaeeaa104a46ddecf9b7c379b59c997a591..6283a6744b12d21e557ad5d3bea71f6d571d6356 100644 (file)
@@ -4,7 +4,6 @@
 
 '''Test cases for constructor and method signature decisor on Time class.'''
 
-import sys
 import os
 import sys
 import unittest
@@ -17,6 +16,7 @@ import datetime
 
 from sample import Time, ImplicitConv, ObjectType
 
+
 class TimeTest(unittest.TestCase):
     '''Test cases for constructor and method signature decisor on Time class.
     The constructor and one method have these signatures: CTORMETHOD() and
@@ -115,6 +115,6 @@ class TimeTest(unittest.TestCase):
         py = datetime.time(12, 32, 5)
         self.assertNotEqual(time, py)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index a938e6af819c6ea7719293b8ef4d77d911709348..7dfd18a4ad671ce4e25134f761cc5e9a09b0ee8c 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import Point, applyHomogeneousTransform
 
+
 class TransformTest(unittest.TestCase):
     '''Test cases for modifying a function with > 9 arguments.'''
 
@@ -32,5 +33,6 @@ class TransformTest(unittest.TestCase):
         r = applyHomogeneousTransform(p, 1, 0, 0, 0, 1, 0, 0, 0, 0)
         self.assertTrue(r is None)
 
+
 if __name__ == '__main__':
     unittest.main()
index 14caf9f498b71f48e634c298998a19a817672f51..987ba6dfda19006eef60e536943d4582a5c5932b 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 import sample
 
+
 class GetPythonTypeByNameTest(unittest.TestCase):
 
     '''Uses an added function with inject code that uses the libshiboken
@@ -176,6 +177,14 @@ class PrimitiveConversionTest(unittest.TestCase):
         point.setX(large_int)
         self.assertEqual(round(point.x()), large_int)
 
+    def testUnsignedLongLongAsFloat(self):
+        """PYSIDE-2652: When passing an unsigned long long to a function taking float,
+           an unsigned 64bit conversion should be done."""
+        point = sample.PointF(1, 2)
+        large_int = 2**63
+        point.setX(large_int)
+        self.assertEqual(round(point.x()), large_int)
+
 
 if __name__ == '__main__':
     unittest.main()
index 1b47c62bcc9a8a58943f4121917aa6a60d8d0ddc..ce881e80222bd0c3d60e78b606806a48df1d9d7b 100644 (file)
@@ -33,12 +33,16 @@ class TypeDeallocTest(unittest.TestCase):
 
     def testScopeEnd(self):
         ref = None
+
         def scope():
+
             class Ext(Point):
                 pass
-            o = Ext()
+
+            o = Ext()  # noqa: F841
             global ref
             ref = weakref.ref(Ext, self.callback)
+
         scope()
         gc.collect()
         self.assertTrue(self.called)
@@ -46,7 +50,7 @@ class TypeDeallocTest(unittest.TestCase):
     def testDeleteType(self):
         class Ext(Point):
             pass
-        ref = weakref.ref(Ext, self.callback)
+        ref = weakref.ref(Ext, self.callback)  # noqa: F841
         del Ext
         gc.collect()
         self.assertTrue(self.called)
@@ -54,4 +58,3 @@ class TypeDeallocTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index c486f2bcc9b476aa22d1cc497452a708a084c6ce..ab8e535b5c3a97ee52d0f4fa3c3a8a69eff29278 100644 (file)
@@ -12,6 +12,7 @@ from shiboken_paths import init_paths
 init_paths()
 from sample import ObjectType
 
+
 class TestTypeDestructorDoubleFree(unittest.TestCase):
     def testTypeDestructorDoubleFree(self):
         '''Causes the type destructors of two derived classes to be called.'''
@@ -22,13 +23,16 @@ class TestTypeDestructorDoubleFree(unittest.TestCase):
             obj = ExtObj1()
             child = ObjectType(parent=obj)
             self.assertEqual(obj.takeChild(child), child)
+
             class ExtObj2(ObjectType):
                 def __init__(self):
                     ObjectType.__init__(self)
+
             obj = ExtObj2()
             child = ObjectType(parent=obj)
             self.assertEqual(obj.takeChild(child), child)
         scope()
 
+
 if __name__ == '__main__':
     unittest.main()
index 40ca587552cd3317b8367ae85507cddad76da50d..e315e599e2a81e9a79647c311c3ae1a4ade6d1f8 100644 (file)
     </value-type>
 
     <value-type name="ClassWithFunctionPointer">
-        <suppress-warning text="^skipping function 'void ClassWithFunctionPointer::callFunctionPointer.*$" />
+        <suppress-warning text="^skipping public function 'void ClassWithFunctionPointer::callFunctionPointer.*$" />
     </value-type>
 
     <value-type name="IntArray" generate="no"/>
         <modify-function signature="hideFunction(HideType*)" remove="all"/>
         <modify-field name="toBeRenamedField" rename="renamedField"/>
         <modify-field name="readOnlyField" write="false"/>
+        <modify-function signature="virtualWithOutParameter(int&amp;)const">
+            <inject-code class="shell" position="override">
+            x = virtualWithOutParameterPyOverride(gil, pyOverride.object());
+            return;
+            </inject-code>
+        </modify-function>
+        <add-function signature="virtualWithOutParameterPyOverride()"
+                      return-type="int" python-override="true"/>
     </object-type>
 
     <object-type name="Derived" polymorphic-id-expression="%1->type() == Derived::TpDerived">
             // CHECKTYPE and ISCONVERTIBLE are used here for test purposes, don't change them.
             if (!%CHECKTYPE[ObjectTypeLayout*](layout) &amp;&amp; !%ISCONVERTIBLE[ObjectTypeLayout*](layout))
                 return;
-            // %CHECKTYPE[ObjectTypeLayout*](layout)
-            // %ISCONVERTIBLE[ObjectTypeLayout*](layout)
+            /* %CHECKTYPE[ObjectTypeLayout*](layout) */
+            /* %ISCONVERTIBLE[ObjectTypeLayout*](layout) */
             ObjectTypeLayout* var;
             var = %CONVERTTOCPP[ObjectTypeLayout*](layout);
             // TODO-CONVERTER: erase this
     <suppress-warning text="Shadowing: MDerived2::castToBase3() and MDerived3::castToBase3()" />
     <suppress-warning text="Visibility of function 'publicMethod' modified in class 'MDerived1'" />
 
-    <suppress-warning text="^skipping function 'std::enable_if.*ComparisonTester::operator[!=]=.*ComparisonTester.*$"/>
+    <suppress-warning text="^skipping public function 'std::enable_if.*ComparisonTester::operator[!=]=.*ComparisonTester.*$"/>
 </typesystem>
index 5e54ef6eeee9bfc13a66b8ceea9b91b26ad9ed68..f7f5342ee835f66406c5b38fcefc0fa23c4380bf 100644 (file)
@@ -13,8 +13,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import (ValueWithUnitUser, ValueWithUnitDoubleInch,
-                    ValueWithUnitDoubleMillimeter)
+from sample import ValueWithUnitUser, ValueWithUnitDoubleInch
 
 
 class TypeSysTypeDefTest(unittest.TestCase):
index dbc4097da86d62ed2712a0b8cabe70bf633ecb30..2a7e5cac7a32ffd7c743e49cf247e9922a2a7497 100644 (file)
@@ -15,6 +15,7 @@ init_paths()
 
 from sample import ObjectType
 
+
 class DerivedObjectType(ObjectType):
     def isPython(self):
         return True
@@ -22,12 +23,13 @@ class DerivedObjectType(ObjectType):
     def createChild(self, parent):
         return DerivedObjectType(parent)
 
+
 class ParentTest(unittest.TestCase):
 
     def testUunsafeParent(self):
         o = DerivedObjectType()
         o.callVirtualCreateChild()
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 28cbd96fde2cde1b7cd092f0e78723bb8827eb2d..45d4095b69ccbe9449ccff7d40c283ce915f37f4 100644 (file)
@@ -14,12 +14,13 @@ from shiboken_paths import init_paths
 init_paths()
 from sample import Size
 
+
 class PointTest(unittest.TestCase):
     def testUsingSelfOnCtor(self):
         # This is a user added ctor and no errors should happen!
         s = Size("3x2")
         self.assertEqual(s.height(), 2)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 69c3479c515f763dabf727eead27571cd3dae10b..6be870269c6115c0fb13da9fc9b190ce8e281f21 100644 (file)
@@ -16,10 +16,12 @@ init_paths()
 
 from sample import VirtualDtor
 
+
 class ExtendedVirtualDtor(VirtualDtor):
     def __init__(self):
         VirtualDtor.__init__(self)
 
+
 class VirtualDtorTest(unittest.TestCase):
     '''Test case for virtual destructor.'''
 
@@ -59,4 +61,3 @@ class VirtualDtorTest(unittest.TestCase):
 
 if __name__ == '__main__':
     unittest.main()
-
index 7be424e26b5c07f2f1127c91ba87c7132e0fca2f..52dc66c907334ba754f0c6a21e18d9369e23bc78 100644 (file)
@@ -14,10 +14,11 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import Point, Str, StrList, VirtualDaughter, VirtualMethods
 
 import warnings
 
+
 class ExtendedVirtualMethods(VirtualMethods):
     def __init__(self):
         VirtualMethods.__init__(self)
@@ -36,6 +37,7 @@ class ExtendedVirtualMethods(VirtualMethods):
         # check if recursion is caused by injected code that calls C++.
         return VirtualMethods.recursionOnModifiedVirtual(self, arg) + 10
 
+
 class ExtendedVirtualDaughter(VirtualDaughter):
     def __init__(self, name):
         VirtualDaughter.__init__(self, name)
@@ -45,6 +47,7 @@ class ExtendedVirtualDaughter(VirtualDaughter):
         self.grand_daughter_name_called = True
         return VirtualDaughter.name(self).prepend('Extended')
 
+
 class ExtendedExtendedVirtualDaughter(ExtendedVirtualDaughter):
     def __init__(self, name):
         ExtendedVirtualDaughter.__init__(self, name)
@@ -54,6 +57,7 @@ class ExtendedExtendedVirtualDaughter(ExtendedVirtualDaughter):
         self.grand_grand_daughter_name_called = True
         return ExtendedVirtualDaughter.name(self).prepend('Extended')
 
+
 class VirtualMethodsTest(unittest.TestCase):
     '''Test case for virtual methods'''
 
@@ -66,7 +70,8 @@ class VirtualMethodsTest(unittest.TestCase):
         gc.collect()
 
     def testReimplementedVirtualMethod0(self):
-        '''Test Python override of a virtual method with various different parameters is correctly called from C++.'''
+        '''Test Python override of a virtual method with various different parameters
+           is correctly called from C++.'''
         vm = VirtualMethods()
         evm = ExtendedVirtualMethods()
         pt = Point(1.1, 2.2)
@@ -120,6 +125,6 @@ class PrettyErrorMessageTest(unittest.TestCase):
         obj = ExtendedVirtualMethods()
         self.assertRaises(RuntimeWarning, obj.callStrListToStdList, StrList())
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 1b810e839ceb63298aef8ea1c6e13a7f428c9597..becdf7423807af4da4f6a9df4922514d7c4bad81 100644 (file)
@@ -11,17 +11,17 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
 from shiboken_paths import init_paths
 init_paths()
 
-from sample import *
+from sample import Base1, MDerived1
+
 
 class VisibilityChangeTest(unittest.TestCase):
 
     def testVisibilityChange(self):
         b1 = Base1()
-        b1.publicMethod() # ok...
+        b1.publicMethod()  # ok...
         d1 = MDerived1()
-        self.assertRaises(TypeError, d1.publicMethod);
+        self.assertRaises(TypeError, d1.publicMethod)
+
 
 if __name__ == '__main__':
     unittest.main()
-
-
index 63882cc8ab456ea1e9fa66d9a38ebb44c460e60a..186cb473eb29f0e2dfc3a8a5ce91dc52a093d040 100644 (file)
@@ -16,6 +16,7 @@ init_paths()
 from sample import VoidHolder, Point
 from shiboken6 import Shiboken
 
+
 class VoidHolderTest(unittest.TestCase):
     '''Test case for void pointer manipulation.'''
 
@@ -44,6 +45,6 @@ class VoidHolderTest(unittest.TestCase):
         voidholder = VoidHolder()
         self.assertEqual(voidholder.voidPointer(), None)
 
+
 if __name__ == '__main__':
     unittest.main()
-
index 317dfb53ca0220e7bf0f98bf7f9f59743d9b4a85..01c6d58d5e417b4f8524d2635f8a41d65e0c82f5 100644 (file)
@@ -30,7 +30,7 @@ class WeakrefBasicTest(unittest.TestCase):
     def testBasic(self):
         '''ObjectType weakref'''
         obj = ObjectType()
-        ref = weakref.ref(obj, self.cb)
+        ref = weakref.ref(obj, self.cb)  # noqa: F841
         del obj
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
@@ -39,7 +39,7 @@ class WeakrefBasicTest(unittest.TestCase):
     def testPrivateDtor(self):
         '''PrivateDtor weakref'''
         obj = PrivateDtor.instance()
-        ref = weakref.ref(obj, self.cb)
+        ref = weakref.ref(obj, self.cb)  # noqa: F841
         del obj
         # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion
         gc.collect()
index e3ba10082b48cdd79dadcbbbe96b5bd0150b307d..dfc962db93abd7dc866f2861bc09b55e107ca746 100644 (file)
@@ -13,7 +13,10 @@ init_paths()
 
 from sample import Point
 
-class ExtPoint(Point): pass
+
+class ExtPoint(Point):
+    pass
+
 
 class TestWritableClassDict(unittest.TestCase):
     def testSetattrOnClass(self):
@@ -29,5 +32,6 @@ class TestWritableClassDict(unittest.TestCase):
         pt = ExtPoint()
         self.assertEqual(pt.bar, 321)
 
+
 if __name__ == '__main__':
     unittest.main()
index a1f955752aa84b205d50e76d0dcdaf85e26b249f..9f9f8f5a4d84d09fab5b7e2063d21e33ea847ee9 100644 (file)
@@ -45,6 +45,16 @@ class TestShiboken(unittest.TestCase):
         self.assertTrue(Shiboken.createdByPython(bb))
         bb.disposeObjectType(bb.keepObjectType(obj))
 
+    def testWrapInstancePreserveId(self):
+        """PYSIDE-31: Verify that wrapInstance() returns the existing wrapper
+           even if a base class type is specified."""
+        v = ObjectView()  # inherits ObjectType
+        addresses = Shiboken.getCppPointer(v)
+        self.assertTrue(addresses)
+        address = addresses[0]
+        wrapped = Shiboken.wrapInstance(address, ObjectType)
+        self.assertEqual(id(wrapped), id(v))
+
     def testIsOwnedByPython(self):
         obj = ObjectType()
         self.assertTrue(Shiboken.ownedByPython(obj))
index 2e729321e6c69df11d753f2067a2417be95e7a82..c10d7ab6b4c0f9d5d13abaf0bdab05f2b78888fb 100644 (file)
@@ -20,6 +20,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/smart/stdsharedptrtestbench_wrapper.cpp
 ${CMAKE_CURRENT_BINARY_DIR}/smart/stdsharedptrvirtualmethodtester_wrapper.cpp
 ${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_integer_wrapper.cpp
 ${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_int_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_std_string_wrapper.cpp
 ${CMAKE_CURRENT_BINARY_DIR}/smart/std_wrapper.cpp
 ${CMAKE_CURRENT_BINARY_DIR}/smart/std_optional_int_wrapper.cpp
 ${CMAKE_CURRENT_BINARY_DIR}/smart/std_optional_integer_wrapper.cpp
index 1bec3a28622452f1646802317e966369217d3cf8..8d4272558eb010070553af2a3cae291934ebe0ff 100644 (file)
@@ -262,7 +262,7 @@ class SmartPointerTests(unittest.TestCase):
         self.assertTrue(five > four)
 
         self.assertRaises(NotImplementedError,
-                          lambda : Obj.createNullSharedPtrInteger() == four)
+                          lambda: Obj.createNullSharedPtrInteger() == four)
 
     def testSmartPointerObjectComparison(self):
         """Test a pointee class without comparison operators."""
index be969d0f5afee2ad22755beca6d3401ac763a0ec..bee5735480bb9f6d60bd51acd4c48a71231d2608 100644 (file)
@@ -2,7 +2,6 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
-import gc
 import os
 import sys
 import unittest
index 1933b5334225335fc691788e89b985b947c34d02..ddaab43f5fc0b4d718b03453ce8d641396b1c805 100644 (file)
@@ -2,7 +2,6 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
-import gc
 import os
 import sys
 import unittest
@@ -50,6 +49,15 @@ class StdSharedPtrTests(unittest.TestCase):
         self.assertFalse(np)
         p = StdSharedPtrTestBench.createInt()
         StdSharedPtrTestBench.printInt(p)
+        ip = std.StdIntPtr(42)
+        StdSharedPtrTestBench.printInt(ip)
+
+    def testString(self):
+        np = StdSharedPtrTestBench.createNullString()
+        StdSharedPtrTestBench.printString(np)
+        self.assertFalse(np)
+        p = StdSharedPtrTestBench.createString("bla")
+        StdSharedPtrTestBench.printString(p)
 
     def testVirtuals(self):
         """Test whether code generating virtual function overrides is generated
index 0f4729413b1d894ab6b0502561a3a49cddbf560c..9c7ef2f01c90f50076cdb2395e950fd37781caea 100644 (file)
@@ -2,7 +2,6 @@
 # Copyright (C) 2022 The Qt Company Ltd.
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
 
-import gc
 import os
 import sys
 import unittest
index 261d5f15dff23821537271cf169d941e056d7667..e4a1ef8b7da38f8d66c5d881beb8c9aff029073e 100644 (file)
@@ -50,7 +50,7 @@
                             value-check-method="operator bool"
                             ref-count-method="use_count"
                             reset-method="reset"
-                            instantiations="Integer,int">
+                            instantiations="Integer,int=StdIntPtr,std::string">
             <include file-name="memory" location="global"/>
         </smart-pointer-type>
 
index 24bc890bc0fddd4e0c247614e7268789063118fd..b36ee55a46e383b934816e0c24954b829363755f 100644 (file)
@@ -229,7 +229,12 @@ def _run_deploy_test(example, tmpdirname):
         raise RuntimeError("Error deploying")
 
     suffix = "exe" if sys.platform == "win32" else "bin"
-    binary = f"{tmpdirname}/{main_file.stem}.{suffix}"
+
+    if sys.platform != "darwin":
+        binary = f"{tmpdirname}/{main_file.stem}.{suffix}"
+    else:
+        binary = f"{tmpdirname}/pyside_app_demo.app/Contents/MacOS/{main_file.stem}"
+
     if run_process([binary]) != 0:
         raise RuntimeError("Error running the deployed example")
     return True
index 96910ebd00aec53eec669182f499b7404d4f0408..6c24f417fa686c1ea7eab091300681eea447d3bc 100644 (file)
@@ -50,7 +50,7 @@ def change_log(version: list) -> Path:
 
 
 def is_lts_version(version: list) -> bool:
-    return version[0] == 5 or version[1] == 2
+    return version[0] == 5 or version[1] in (2, 5)
 
 
 def version_tag(version: list) -> str:
@@ -126,7 +126,7 @@ def parse_options() -> Namespace:
         # For major/minor releases, skip all fixes with "Pick-to: " since they
         # appear in bug-fix releases.
         if args.type != "bug-fix":
-           args.exclude = True
+            args.exclude = True
         print(f'Assuming "{args.type}" version', file=sys.stderr)
 
     if args.type not in ("bug-fix", "minor", "major"):
index b09ab7bd9d3a6c389f543d1b8a5556bf8873cdcc..039fa9431cf3a0ad6ebfe983c0e41b3d9f907a02 100644 (file)
@@ -16,7 +16,7 @@ from tqdm import tqdm
 
 # the tag number does not matter much since we update the sdk later
 DEFAULT_SDK_TAG = 6514223
-ANDROID_NDK_VERSION = "25c"
+ANDROID_NDK_VERSION = "26b"
 
 
 def run_command(command: List[str], cwd: str = None, ignore_fail: bool = False,
index 9c4616e97826818787419c105eacd2e8bab9ec8f..bda438ccade38beb47b47738ce283ea6b2923cac 100644 (file)
@@ -18,7 +18,7 @@ from android_utilities import (run_command, download_android_commandlinetools,
                                download_android_ndk, install_android_packages)
 
 # Note: Does not work with PyEnv. Your Host Python should contain openssl.
-PYTHON_VERSION = "3.10"
+PYTHON_VERSION = "3.11"
 
 SKIP_UPDATE_HELP = ("skip the updation of SDK packages build-tools, platform-tools to"
                     " latest version")
@@ -86,7 +86,7 @@ if __name__ == "__main__":
 
     parser.add_argument("-v", "--verbose", help="run in verbose mode", action="store_const",
                         dest="loglevel", const=logging.INFO)
-    parser.add_argument("--api-level", type=str, default="31", help="Android API level to use")
+    parser.add_argument("--api-level", type=str, default="33", help="Android API level to use")
     parser.add_argument("--ndk-path", type=str, help="Path to Android NDK (Preferred r25c)")
     # sdk path is needed to compile all the Qt Java Acitivity files into Qt6AndroidBindings.jar
     parser.add_argument("--sdk-path", type=str, help="Path to Android SDK")
@@ -221,6 +221,7 @@ if __name__ == "__main__":
                     ndk_path=ndk_path,
                     api_level=platform_data.api_level,
                     android_py_install_path_prefix=pyside6_deploy_cache,
+                    host_python_path=sys.executable
                 )
 
                 logging.info(f"Writing Python cross compile script into {python_ccompile_script}")
@@ -288,12 +289,12 @@ if __name__ == "__main__":
         # run the cross compile script
         logging.info(f"Running Qt for Python cross-compile for platform {platform_data.plat_name}")
         qfp_ccompile_cmd = [sys.executable, "setup.py", "bdist_wheel", "--parallel=9",
-                            "--standalone", "--limited-api=yes",
+                            "--standalone",
                             f"--cmake-toolchain-file={str(qfp_toolchain.resolve())}",
                             f"--qt-host-path={qt_install_path}/gcc_64",
                             f"--plat-name=android_{platform_data.plat_name}",
                             f"--python-target-path={python_path}",
                             (f"--qt-target-path={qt_install_path}/"
                                 f"android_{platform_data.qt_plat_name}"),
-                            "--no-qt-tools", "--unity"]
+                            "--no-qt-tools"]
         run_command(qfp_ccompile_cmd, cwd=pyside_setup_dir, dry_run=dry_run, show_stdout=True)
index 85d032e2b21e5d21757a33886647ad50ff58e495..a68907591a4360eb8ded87202b976c994ee0fc45 100644 (file)
@@ -20,7 +20,8 @@ export RANLIB=$TOOLCHAIN/llvm-ranlib
 export LD=$TOOLCHAIN/ld
 export READELF=$TOOLCHAIN/llvm-readelf
 export CFLAGS='-fPIC -DANDROID'
-./configure --host=$HOST_ARCH --target=$HOST_ARCH --build=x86_64-pc-linux-gnu --enable-shared \
+./configure --host=$HOST_ARCH --target=$HOST_ARCH --build=x86_64-pc-linux-gnu \
+--with-build-python={{ host_python_path }}  --enable-shared \
 --enable-ipv6 ac_cv_file__dev_ptmx=yes ac_cv_file__dev_ptc=no --without-ensurepip \
 ac_cv_little_endian_double=yes
 make BLDSHARED="$CC -shared" CROSS-COMPILE=$TOOL_PREFIX- CROSS_COMPILE_TARGET=yes
index a691d50f29582d4f6b058626b465c0443d2d5a1f..3c9752f4358bc919a13b8d6ded1d2eba926c96c0 100644 (file)
@@ -2,7 +2,7 @@
 # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 # toolchain file to cross compile Qt for Python wheels for Android
-cmake_minimum_required(VERSION 3.18)
+cmake_minimum_required(VERSION 3.23)
 include_guard(GLOBAL)
 set(CMAKE_SYSTEM_NAME Android)
 {% if plat_name == "armv7a" -%}
index 40faff133836119df67fbd91c4a09b40b2dc2a14..b5aa632c046c88873aa392025d29d5468a28f09f 100644 (file)
@@ -20,7 +20,7 @@ import zipfile
 import sys
 from argparse import ArgumentParser, RawTextHelpFormatter
 from dataclasses import dataclass
-from enum import Enum
+from enum import IntEnum, Enum
 from pathlib import Path
 from textwrap import dedent
 
@@ -30,6 +30,12 @@ class Format(Enum):
     MD = 1
 
 
+class ModuleType(IntEnum):
+    ESSENTIALS = 0
+    ADDONS = 1
+    M2M = 2
+
+
 SUFFIXES = {Format.RST: "rst", Format.MD: "md"}
 
 
@@ -100,6 +106,87 @@ def check_img_ext(i):
     return i.suffix in IMAGE_SUFFIXES
 
 
+@dataclass
+class ModuleDescription:
+    """Specifies a sort key and type for a Qt module."""
+    sort_key: int = 0
+    module_type: ModuleType = ModuleType.ESSENTIALS
+    description: str = ''
+
+
+MODULE_DESCRIPTIONS = {
+    "async": ModuleDescription(16, ModuleType.ESSENTIALS, ''),
+    "corelib": ModuleDescription(15, ModuleType.ESSENTIALS, ''),
+    "dbus": ModuleDescription(22, ModuleType.ESSENTIALS, ''),
+    "designer": ModuleDescription(11, ModuleType.ESSENTIALS, ''),
+    "gui": ModuleDescription(25, ModuleType.ESSENTIALS, ''),
+    "network": ModuleDescription(20, ModuleType.ESSENTIALS, ''),
+    "opengl": ModuleDescription(26, ModuleType.ESSENTIALS, ''),
+    "qml": ModuleDescription(0, ModuleType.ESSENTIALS, ''),
+    "quick": ModuleDescription(1, ModuleType.ESSENTIALS, ''),
+    "quickcontrols": ModuleDescription(2, ModuleType.ESSENTIALS, ''),
+    "samplebinding": ModuleDescription(30, ModuleType.ESSENTIALS, ''),
+    "scriptableapplication": ModuleDescription(30, ModuleType.ESSENTIALS, ''),
+    "sql": ModuleDescription(21, ModuleType.ESSENTIALS, ''),
+    "uitools": ModuleDescription(12, ModuleType.ESSENTIALS, ''),
+    "widgetbinding": ModuleDescription(30, ModuleType.ESSENTIALS, ''),
+    "widgets": ModuleDescription(10, ModuleType.ESSENTIALS, ''),
+    "xml": ModuleDescription(24, ModuleType.ESSENTIALS, ''),
+    "Qt Demos": ModuleDescription(0, ModuleType.ADDONS, ''),  # from Qt repos
+    "3d": ModuleDescription(30, ModuleType.ADDONS, ''),
+    "axcontainer": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "bluetooth": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "charts": ModuleDescription(12, ModuleType.ADDONS, ''),
+    "datavisualization": ModuleDescription(11, ModuleType.ADDONS, ''),
+    "demos": ModuleDescription(0, ModuleType.ADDONS, ''),
+    "external": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "graphs": ModuleDescription(10, ModuleType.ADDONS, ''),
+    "httpserver": ModuleDescription(0, ModuleType.ADDONS, ''),
+    "location": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "multimedia": ModuleDescription(12, ModuleType.ADDONS, ''),
+    "networkauth": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "pdf": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "pdfwidgets": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "quick3d": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "remoteobjects": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "serialbus": ModuleDescription(30, ModuleType.ADDONS, ''),
+    "serialport": ModuleDescription(30, ModuleType.ADDONS, ''),
+    "spatialaudio": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "speech": ModuleDescription(20, ModuleType.ADDONS, ''),
+    "statemachine": ModuleDescription(30, ModuleType.ADDONS, ''),
+    "webchannel": ModuleDescription(30, ModuleType.ADDONS, ''),
+    "webenginequick": ModuleDescription(15, ModuleType.ADDONS, ''),
+    "webenginewidgets": ModuleDescription(16, ModuleType.ADDONS, ''),
+    "coap": ModuleDescription(0, ModuleType.M2M, ''),
+    "mqtt": ModuleDescription(0, ModuleType.M2M, ''),
+    "opcua": ModuleDescription(0, ModuleType.M2M, '')
+}
+
+
+def module_sort_key(name):
+    """Return key for sorting modules."""
+    description = MODULE_DESCRIPTIONS.get(name)
+    module_type = int(description.module_type) if description else 5
+    sort_key = description.sort_key if description else 100
+    return f"{module_type}:{sort_key:04}:{name}"
+
+
+def module_title(name):
+    """Return title for a module."""
+    result = name.title()
+    description = MODULE_DESCRIPTIONS.get(name)
+    if description:
+        if description.description:
+            result += " - " + description.description
+        if description.module_type == ModuleType.M2M:
+            result += " (M2M)"
+        elif description.module_type == ModuleType.ADDONS:
+            result += " (Add-ons)"
+        else:
+            result += " (Essentials)"
+    return result
+
+
 @dataclass
 class ExampleData:
     """Example data for formatting the gallery."""
@@ -498,10 +585,15 @@ def write_example(example_root, pyproject_file, pyside_example=True):
     return (p.module_name, result)
 
 
+def example_sort_key(example: ExampleData):
+    name = example.example
+    return "AAA" + name if "gallery" in name else name
+
+
 def sort_examples(example):
     result = {}
     for module in example.keys():
-        result[module] = sorted(example.get(module), key=lambda e: e.doc_file)
+        result[module] = sorted(example.get(module), key=example_sort_key)
     return result
 
 
@@ -548,7 +640,7 @@ if __name__ == "__main__":
         shutil.rmtree(EXAMPLES_DOC, ignore_errors=True)
         if not opt_quiet:
             print("WARNING: Deleted old html directory")
-    EXAMPLES_DOC.mkdir()
+    EXAMPLES_DOC.mkdir(exist_ok=True)
 
     scan_examples_dir(EXAMPLES_DIR)
     if options.qt_src_dir:
@@ -578,11 +670,13 @@ if __name__ == "__main__":
     index_files = []
     with open(f"{EXAMPLES_DOC}/index.rst", "w") as f:
         f.write(BASE_CONTENT)
-        for module_name, e in sorted(examples.items()):
+        for module_name in sorted(examples.keys(), key=module_sort_key):
+            e = examples.get(module_name)
             for i in e:
                 index_files.append(i.doc_file)
-            f.write(f"{module_name.title()}\n")
-            f.write(f"{'*' * len(module_name.title())}\n")
+            title = module_title(module_name)
+            f.write(f"{title}\n")
+            f.write(f"{'*' * len(title)}\n")
             f.write(get_module_gallery(e))
         f.write("\n\n")
         f.write(footer_index)
index 4992e170b3536d3bb50e9d8e9a1d052e1e76c5a9..df4c7557c99c9c23548c58164f8b7fe17ae90ca5 100644 (file)
@@ -532,6 +532,7 @@ module_classes = {
         "QAccessibleEvent",
         "QAccessibleInterface",
         "QAccessibleObject",
+        "QAccessibleSelectionInterface",
         "QAccessibleStateChangeEvent",
         "QAccessibleTableCellInterface",
         "QAccessibleTableModelChangeEvent",
index 9e8546e80f592d7e05f09d9aaaad8de35573c47e..2e30e9ae90a7881849f2ae101c59ef8f3bb7116b 100644 (file)
@@ -10,7 +10,7 @@ authors = [
 description = PROJECT_DESCRIPTION
 readme = PROJECT_README
 dynamic = ["version"]
-requires-python = ">=3.8, <3.13"
+requires-python = ">=3.9, <3.13"
 keywords = ["Qt"]
 license = {text = "LGPL"}
 dependencies = PROJECT_DEPENDENCIES
@@ -31,7 +31,6 @@ classifiers = [
     "Programming Language :: C++",
     "Programming Language :: Python",
     "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.8",
     "Programming Language :: Python :: 3.9",
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
@@ -54,7 +53,7 @@ Tracker = "https://bugreports.qt.io/projects/PYSIDE"
 PROJECT_SCRIPTS
 
 [tool.distutils.bdist_wheel]
-py_limited_api = "cp38"
+py_limited_api = "cp39"
 plat_name = PROJECT_TAG
 
 [tool.setuptools.dynamic]